Login session model combat
Introduction
Login session is a basic operation, no matter which application will use the module, in response to this, I wrote a simple case for the previous spring security function article
Operating procedures
Database Design
Operation link: User Center-Database Design
curd operation tool
Operation link: Springboot implants pagerHelper and spring mybatis to update several operations
Login authentication implementation
Login code
Here is a simple user name and password operation, query user resource path, query user information through user phone number, and match password. The specific code is as follows:
/**
* 电话号码登录
* @param phone 用户电话号码
* @param password 加密后密码
* @return
*/
@Override
public UserData login(String phone, @NotNull String password) {
Example example = new Example(User.class);
example.createCriteria().andEqualTo("userPhone", phone);
User user = userMapper.selectOneByExample(example);
if (user != null && password.equals(user.getUserPassword())) {
UserData userData = new UserData();
/**
* 查询用户资源信息
*/
userData.setUserResources(resourceMapper.selectResourceByRoleId(user.getId()));
BeanUtils.copyProperties(user, userData);
Logon logon = new Logon();
logon.setToken(UUID.randomUUID().toString().replaceAll("-", ""));
logon.setUserId(user.getId());
try {
logon.setResourceData(objectMapper.writeValueAsString(userData.getUserResources()));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
Example logonExample = new Example(Logon.class);
logonExample.createCriteria().andEqualTo("userId", user.getId());
logonMapper.deleteByExample(logonExample);
logonMapper.insert(logon);
userData.setToken(logon.getToken());
return userData;
}
return null;
}
User resource query
Query the sql configuration of user resources
<select id="selectResourceByRoleId" resultMap="BaseResultMap">
SELECT `tb_resource`.`id`,
`resource_code`,
`resource_url`,
`resource_description`,
`resource_state`
FROM `tb_resource`
RIGHT JOIN `role_resource`
ON `tb_resource`.`id` = `role_resource`.`resource_id`
RIGHT JOIN `user_role`
ON `user_role`.`role_id` = `role_resource`.`role_id`
WHERE `user_role`.`user_id` = #{userId}
</select>
Login interface
Specific login controller code
package com.lgh.controller;
import com.lgh.common.result.CommonResult;
import com.lgh.common.result.inter.IResult;
import com.lgh.model.domain.UserData;
import com.lgh.service.ILogonService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
@Api(tags = "登录服务")
@RestController
@RequestMapping("/login")
@Validated
public class LogonController {
@Autowired
private ILogonService logonService;
@ApiOperation("登录服务接口")
@PostMapping("/sign")
@Valid
public IResult<UserData> login(@NotNull @RequestParam("phone") String phone, @NotNull @RequestParam("password") String password) {
UserData userData = logonService.login(phone, password);
return CommonResult.successData(userData);
}
}
Authentication and authentication
Intercept authentication through spring security filters, and authorization through annotation @RolesAllowed. Because the spring security filter cannot be managed by spring, otherwise it will be intercepted globally, so here you need to get the request interface, get the bean of the service, so get the application class first.
ApplicationUtil tool class
package com.lgh.common.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class ApplicationUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public static <T> T getBean(Class<T> t) {
return applicationContext.getBean(t);
}
}
GrantedAuthority permission control class
Since jsr250 will add a prefix, I don’t like the prefix ROLE_, so I also give the prefix by default when I implement GrantedAuthority, as shown in the following code
package com.lgh.common.authority.authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.util.Assert;
public class MySimpleGrantedAuthority implements GrantedAuthority {
private static final long serialVersionUID = 510L;
private final String rolePrefix = "ROLE_";
private final String role;
public MySimpleGrantedAuthority(String role) {
Assert.hasText(role, "A granted authority textual representation is required");
this.role = role;
}
public String getAuthority() {
return rolePrefix + this.role;
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else {
return obj instanceof MySimpleGrantedAuthority ? this.role.equals(((MySimpleGrantedAuthority) obj).role) : false;
}
}
public int hashCode() {
return this.role.hashCode();
}
public String toString() {
return this.role;
}
}
security Filter authentication
Let's write the actual filter
package com.lgh.common.authority.filter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lgh.common.authority.authentication.MyAuthentication;
import com.lgh.common.authority.authentication.MySimpleGrantedAuthority;
import com.lgh.common.authority.entity.UserDetail;
import com.lgh.common.result.CommonResult;
import com.lgh.common.util.ApplicationUtil;
import com.lgh.model.Resource;
import com.lgh.model.domain.UserData;
import com.lgh.service.ILogonService;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* spring security过滤器,不要交给spring 管理
*/
public class MyAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String token = request.getHeader("token");
if (StringUtils.isEmpty(token)) {
filterChain.doFilter(request, response);
} else {
ILogonService logonService = ApplicationUtil.getBean(ILogonService.class);
UserData userData = logonService.verify(token);
if (userData == null) {
ObjectMapper objectMapper = ApplicationUtil.getBean(ObjectMapper.class);
response.setContentType("application/json;charset=utf-8");
response.getWriter().print(objectMapper.writeValueAsString(CommonResult.deny()));
return;
} else {
UserDetail userDetail = new UserDetail();
userDetail.setId(userData.getId());
userDetail.setName(userData.getUserName());
List<MySimpleGrantedAuthority> roles = new ArrayList<>();
if (userData.getUserResources() != null) {
roles = userData.getUserResources().stream()
.map(Resource::getResourceCode)
.map(MySimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
MyAuthentication myAuthentication = new MyAuthentication(userDetail, roles);
SecurityContextHolder.getContext().setAuthentication(myAuthentication);
filterChain.doFilter(request, response);
}
}
}
}
test
- Initialize user information, initialize yourself according to the form
- swagger test, as shown below
- After logging in, get the corresponding token and request a sample, as shown in the figure
to sum up
- You can learn simple user-centric user design from the article
- How to use pagerHelper function
- Login process design
- The use and design of security authentication and common problems (The filter cannot be handed over to spring, set the path to not check web.ignoring(), and the processing of the permission check prefix)