Security 登录功能实现

通过 Security 登录功能实现

Security pom包引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>

WebSecurityConfig 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {

String[] pathArray = new String[] {"/user/captcha/base64Code","/user/send/sms/verifyCode","/user/forget/password"};
http.cors();
http.csrf().disable();
http.authorizeRequests()
.anyRequest().authenticated()
// 请求访问控制
.accessDecisionManager(accessDecisionManager())
.antMatchers(pathArray).permitAll()
.anyRequest().authenticated();

http.formLogin()
.loginProcessingUrl("/user/login")
//登录成功
.successHandler(authSuccessHandler())
//登录失败
.failureHandler(failureHandler())
.permitAll();

http.logout()
.logoutUrl("/logout")
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
//退出成功
.logoutSuccessHandler(logoutSuccessHandler())
.permitAll();
http.exceptionHandling()
//未授权拦截调转
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint())
.accessDeniedHandler(accessDeniedHandler());
}
@Autowired
private UserDetailsService userDetailsService;

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
System.out.println("configure");
auth.userDetailsService(userDetailsService);
}

@Bean
@Override
protected AuthenticationManager authenticationManager() {
System.out.println("authenticationManager");
return new UserAuthenticationManager();
}

@Bean
AuthenticationSuccessHandler authSuccessHandler() {
return new UserAuthenticationHandler();
}

@Bean
AuthenticationFailureHandler failureHandler() {
return new UserFailureHandler();
}

@Bean
public AccessDecisionManager accessDecisionManager() {
List<AccessDecisionVoter<?>> decisionVoters = Arrays.asList(
new RoleVoter(),
authorityVoter()
);
return new UnanimousBased(decisionVoters);
}

@Bean
UserAccessDecisionVoter authorityVoter() {
return new UserAccessDecisionVoter();
}

@Bean
LogoutSuccessHandler logoutSuccessHandler() {
return new UserLogoutSuccessHandler();
}

@Bean
AccessDeniedHandler accessDeniedHandler() {
return new UserAccessDeniedHandler();
}

UserDetailsService 用户查询服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
/**
* 通过用户名查询用户详细信息
* @param username
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("loadUserByUsername");
//查询 User
return null;
}
}

UserAccessDecisionVoter 投票器

可以动态实现对请求地址的拦截

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class UserAccessDecisionVoter implements AccessDecisionVoter {
@Override
public boolean supports(ConfigAttribute attribute) {
return true;
}

@Override
public int vote(Authentication authentication, Object object, Collection collection) {
System.out.println("UserAccessDecisionVoter");
FilterInvocation fi = (FilterInvocation) object;
System.out.println(fi.getRequestUrl());
return 1;
}

@Override
public boolean supports(Class clazz) {
return clazz.equals(FilterInvocation.class);
}
}

UserAuthenticationManager 用户授权管理

对不同方式登录的用户授权,如快捷登录,扫码登录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class UserAuthenticationManager implements AuthenticationManager {

private static final Logger LOGGER = LoggerFactory.getLogger(UserAuthenticationManager.class);
@Reference(version = "1.0")
private UserService userService;

private final List<GrantedAuthority> AUTHORITIES = new ArrayList<>();

public UserAuthenticationManager() {
AUTHORITIES.add(new SimpleGrantedAuthority("ROLE_USER"));
}

@Override
public Authentication authenticate(Authentication auth) throws AuthenticationException {

if (check(auth)) {
LOGGER.info("UserAuthenticationManager -->");
return new UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(), AUTHORITIES);
}
throw new BadCredentialsException("Bad Credentials");
}
...
}

UserAuthenticationHandler 登录成功

1
2
3
4
5
6
7
8
9
10
public class UserAuthenticationHandler extends SimpleUrlAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request
, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.setCharacterEncoding("UTF-8");
System.out.println("onAuthenticationSuccess");
// 定义调转方式
// JSON.writeJSONString(response.getWriter(), result);
}
}

UserFailureHandler 登录失败

对登录失败异常定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class UserFailureHandler extends SimpleUrlAuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response
, AuthenticationException exception) throws IOException, ServletException {
response.setCharacterEncoding("UTF-8");
logger.info("onAuthenticationFailure "+exception.getMessage(),exception);

if(exception instanceof BadCredentialsException){
String[] array = exception.getMessage().split("=");
if(array.length>1){
JSON.writeJSONString(response.getWriter(), TeResponse.error(array[0],array[1]));
return;
}
}
JSON.writeJSONString(response.getWriter(), TeResponse.error(StateEnum.S_1004));
}
}

UserLogoutSuccessHandler 退出成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class UserLogoutSuccessHandler implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
SessionUtil.removeSessionAttribute(Const.LOGIN_SESSION_KEY, request);
SecurityContextHolder.clearContext();
response.setCharacterEncoding("UTF-8");
JSON.writeJSONString(response.getWriter(), TeResponse.success());
}
}

### UserAccessDeniedHandler 自定义权限不足
```java
public class UserAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
TeUser user = SessionUtil.getSessionAttribute(Const.LOGIN_SESSION_KEY, request);
System.out.println("UserAccessDeniedHandler");
response.setCharacterEncoding("UTF-8");
if (null == user) {
JSON.writeJSONString(response.getWriter(), TeResponse.error(StateEnum.S_401));
}
else{
JSON.writeJSONString(response.getWriter(), TeResponse.error(StateEnum.S_403));
}
}
}

UserAccessDeniedHandler 认证用户无权限访问异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class UserAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
TeUser user = SessionUtil.getSessionAttribute(Const.LOGIN_SESSION_KEY, request);
System.out.println("UserAccessDeniedHandler");
response.setCharacterEncoding("UTF-8");
if (null == user) {
JSON.writeJSONString(response.getWriter(), TeResponse.error(StateEnum.S_401));
}
else{
JSON.writeJSONString(response.getWriter(), TeResponse.error(StateEnum.S_403));
}
}
}

LoginUrlAuthenticationEntryPoint 未登录无权限访问异常

1
2
3
4
5
6
7
8
9
10
11
public class LoginUrlAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
System.out.println("LoginUrlAuthenticationEntryPoint");
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
out.write(JsonUtil.toJSON(TeResponse.error(StateEnum.S_401)));
out.flush();
out.close();
}
}