幻灯片 1
幻灯片 2
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
幻灯片 3
幻灯片 4
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login</title>
<link href="maxcdn.bootstrapcdn.com/bootstrap/4…" rel="stylesheet" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
<link href="getbootstrap.com/docs/4.0/ex…" rel="stylesheet" crossorigin="anonymous"/>
</head>
<body>
<div class="container">
<form class="form-signin" method="post" action="/login">
<h2 class="form-signin-heading">CLX-Please sign in</h2>
<p>
<label for="username" class="sr-only">Username</label>
<input type="text" id="username" name="username" class="form-control" placeholder="Username" required autofocus>
</p>
<p>
<label for="password" class="sr-only">Password</label>
<input type="password" id="password" name="password" class="form-control" placeholder="Password" required>
</p>
<input name="_csrf" type="hidden" value="c66eed70-0fde-4120-9f32-1e035ab5f06c" />
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
</body>
</html>
幻灯片 5
public class CustomPasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return s.equals(charSequence.toString());
}
}
幻灯片 6
@Configuration
public class CustomWebMvcConfigure implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login.html");
}
}
@Configuration public class CustomSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new CustomPasswordEncoder()).
withUser("admin").password("admin").roles("ADMIN")
.and()
.withUser("clx").password("clx").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and().formLogin().loginPage("/login").permitAll()
.and().csrf().disable();
}
}
幻灯片 7
幻灯片 8
幻灯片 9
幻灯片 10
@Configuration public class CustomSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
CustomAuthentlcationProvider customAuthentlcationProvider;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthentlcationProvider);
// auth.inMemoryAuthentication().passwordEncoder(new CustomPasswordEncoder()).
// withUser("admin").password("admin").roles("ADMIN")
// .and()
// .withUser("clx").password("clx").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and().formLogin().loginPage("/login").permitAll()
.and().csrf().disable();
}
}
幻灯片 11
@Component public class CustomAuthentlcationProvider implements AuthenticationProvider {
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// 获取用户名
String username = (String)authentication.getPrincipal();
// 获取密码
String password = (String)authentication.getCredentials();
*// TODO 此处可以进行加密处理
// 后台处理得到的密码*
UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);
if(!password.equals(userDetails.getPassword())) {
throw new BadCredentialsException("用户名和密码不正确,请重新登录");
}
return new UsernamePasswordAuthenticationToken(username, password, userDetails.getAuthorities());
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
幻灯片 12
@Component
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private CustomUserDetails customUserDetails;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
// TODO 从数据库里面查或者从LDAP里面查
customUserDetails**.setUsername(s);
customUserDetails.setPassword("test");
return customUserDetails;
}
}
幻灯片 13
@Component
public class CustomUserDetails implements UserDetails, Serializable {
private String username;
private String password;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
@Override
public String getPassword() {
return this.password;
}
@Override
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
//-----为了测试,暂时都设置为True,默认false-----Start
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
//-----为了测试,暂时都设置为True,默认false-----End
}
幻灯片 14
幻灯片 15
幻灯片 16
幻灯片 17
CustomResponseBody:
public class CustomResponseBody implements Serializable {
private String status;
private String msg;
private String result;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
}
---------------------------------------------------------------
CustomAuthenticationEntryPoint
@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
CustomResponseBody customResponseBody = new CustomResponseBody();
customResponseBody.setStatus("01");
customResponseBody.setMsg("Need Login");
httpServletResponse.getWriter().write(JSON.toJSONString(customResponseBody));
}
}
-----------------------------------------------------------------------
CustomSecurityConfigurer
@Configuration public class CustomSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
CustomAuthentlcationProvider customAuthentlcationProvider;
@Autowired
CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthentlcationProvider);
// auth.inMemoryAuthentication().passwordEncoder(new CustomPasswordEncoder()).
// withUser("admin").password("admin").roles("ADMIN")
// .and()
// .withUser("clx").password("clx").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().authenticationEntryPoint(customAuthenticationEntryPoint)
.and()
.authorizeRequests().anyRequest().authenticated()
.and().formLogin().loginPage("/login").permitAll()
.and().csrf().disable();
}
}
幻灯片 18
幻灯片 19
@Component
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
CustomResponseBody customResponseBody = new CustomResponseBody();
customResponseBody.setStatus("02");
customResponseBody.setMsg("Login success");
httpServletResponse.getWriter().write(JSON.toJSONString(customResponseBody));
}
}
---------------------------------------------------------------
CustomSecurityConfigurer
@Configuration public class CustomSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
CustomAuthentlcationProvider customAuthentlcationProvider;
@Autowired
CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
@Autowired
CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
@Autowired
CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthentlcationProvider);
// auth.inMemoryAuthentication().passwordEncoder(new CustomPasswordEncoder()).
// withUser("admin").password("admin").roles("ADMIN")
// .and()
// .withUser("clx").password("clx").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().authenticationEntryPoint(customAuthenticationEntryPoint)
.and()
.authorizeRequests().anyRequest().authenticated()
.and().formLogin().loginPage("/login")
.successHandler(customAuthenticationSuccessHandler)
.failureHandler(customAuthenticationFailureHandler)
.permitAll()
.and().csrf().disable();
}
}
幻灯片 20
幻灯片 21
@Component
public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
CustomResponseBody customResponseBody = new CustomResponseBody();
customResponseBody.setStatus("03");
customResponseBody.setMsg("Login fail");
httpServletResponse.getWriter().write(JSON.toJSONString(customResponseBody));
}
}
--------------------------------------------------------------------------------------
CustomSecurityConfigurer
@Configuration public class CustomSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
CustomAuthentlcationProvider customAuthentlcationProvider;
@Autowired
CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
@Autowired
CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
@Autowired
CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthentlcationProvider);
// auth.inMemoryAuthentication().passwordEncoder(new CustomPasswordEncoder()).
// withUser("admin").password("admin").roles("ADMIN")
// .and()
// .withUser("clx").password("clx").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().authenticationEntryPoint(customAuthenticationEntryPoint)
.and()
.authorizeRequests().anyRequest().authenticated()
.and().formLogin().loginPage("/login")
.successHandler(customAuthenticationSuccessHandler)
.failureHandler(customAuthenticationFailureHandler)
.permitAll()
.and().csrf().disable();
}
}
幻灯片 22
幻灯片 23
幻灯片 24
幻灯片 25
CustomUserDetailsService
@Component
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private CustomUserDetails customUserDetails;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
// TODO 从数据库里面查或者从LDAP里面查
customUserDetails**.setUsername(s);
customUserDetails.setPassword("test");
Set authoritiesSet = new HashSet();
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_AAA");
authoritiesSet.add(grantedAuthority);
customUserDetails.setAuthorities(authoritiesSet);
return customUserDetails;
}
}
-------------------------------------------------------------
CustomUserDetails
@Component
public class CustomUserDetails implements UserDetails, Serializable {
private String username;
private String password;
// 权限
private Set<? extends GrantedAuthority> authorities;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.authorities;
}
public void setAuthorities(Set<? extends GrantedAuthority> authorities) {
this.authorities = authorities;
}
@Override
public String getPassword() {
return this.password;
}
@Override
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
//-----为了测试,暂时都设置为True,默认false-----Start
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
//-----为了测试,暂时都设置为True,默认false-----End
}
幻灯片 26
幻灯片 27
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
CustomResponseBody customResponseBody = new CustomResponseBody();
customResponseBody.setStatus("04");
customResponseBody.setMsg("Login Access Denied");
httpServletResponse.getWriter().write(JSON.toJSONString(customResponseBody));
}
}
-----------------------------------------------------------------------------------
http.exceptionHandling().accessDeniedHandler(customAccessDeniedHandler);
幻灯片 28
幻灯片 29
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
CustomResponseBody customResponseBody = new CustomResponseBody();
customResponseBody.setStatus("04");
customResponseBody.setMsg("Login Access Denied");
httpServletResponse.getWriter().write(JSON.toJSONString(customResponseBody));
}
}
-----------------------------------------------------------------------------------
http.exceptionHandling().accessDeniedHandler(customAccessDeniedHandler);
幻灯片 30
CustomAuthentlcationProvider:
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// 获取用户名
String username = (String)authentication.getPrincipal();
// 获取密码
String password = (String)authentication.getCredentials();
*// TODO 此处可以进行加密处理
// 后台处理得到的密码*
UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);
if(!password.equals(userDetails.getPassword())) {
throw new BadCredentialsException("用户名和密码不正确,请重新登录");
}
// return new UsernamePasswordAuthenticationToken(username, password, userDetails.getAuthorities());
return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
}
--------------------------------------------------------------------------------------------------
RbacService.java
@Component("rbacservice")
public class RbacService {
public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
Object userInfo = authentication.getPrincipal();
boolean hasPermission = false;
if (userInfo instanceof CustomUserDetails) {
String username = ((CustomUserDetails) userInfo).getUsername();
// TODO 从数据库获取资源
Set urls = new HashSet<>();
// urls.add("/clxTest1.html");
urls.add("/clxTest.html");
Set set2 = new HashSet<>();
Set set3 = new HashSet<>();
AntPathMatcher antPathMatcher = new AntPathMatcher();
for (String url : urls) {
if (antPathMatcher.match(url, request.getRequestURI())) {
hasPermission = true;
break;
}
}
return hasPermission;
} else {
return false;
}
}
}
-----------------------------------------------------------------------------------------------
CustomSecurityConfigurer
@Configuration public class CustomSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
CustomAuthentlcationProvider customAuthentlcationProvider;
@Autowired
CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
@Autowired
CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
@Autowired
CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
@Autowired
CustomAccessDeniedHandler customAccessDeniedHandler;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthentlcationProvider);
// auth.inMemoryAuthentication().passwordEncoder(new CustomPasswordEncoder()).
// withUser("admin").password("admin").roles("ADMIN")
// .and()
// .withUser("clx").password("clx").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().authenticationEntryPoint(customAuthenticationEntryPoint)
.and()
.authorizeRequests()
.antMatchers("/**/webjars/**").permitAll()
.antMatchers("/**/swagger-ui.html").permitAll()
.antMatchers("/**/swagger-resources/**").permitAll()
.antMatchers("/**/swagger-ui/**").permitAll()
.antMatchers("/**/v2/api-docs").permitAll()
// 这种方式代码中会写死
// .antMatchers("/clxTest.html").hasRole("AAA")
.anyRequest() .access("@rbacservice.hasPermission(request, authentication)") // .authenticated() .and().formLogin().loginPage("/login") .successHandler(customAuthenticationSuccessHandler) .failureHandler(customAuthenticationFailureHandler) .permitAll() .and().csrf().disable();
http.exceptionHandling().accessDeniedHandler(customAccessDeniedHandler);
}
}
幻灯片 31
Login.html 加入remember-me:
<html lang="en" xmlns:c="www.w3.org/1999/XSL/Tr…
<head>
<meta charset="UTF-8">
<title>Login</title>
<link href="maxcdn.bootstrapcdn.com/bootstrap/4…" rel="stylesheet" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
<link href="getbootstrap.com/docs/4.0/ex…" rel="stylesheet" crossorigin="anonymous"/>
</head>
<body>
<div class="container">
<form class="form-signin" method="post" action="/login">
<h2 class="form-signin-heading">CLX-Please sign in</h2>
<p>
<label for="username" class="sr-only">Username</label>
<input type="text" id="username" name="username" class="form-control" placeholder="Username" required autofocus>
</p>
<p>
<label for="password" class="sr-only">Password</label>
<input type="password" id="password" name="password" class="form-control" placeholder="Password" required>
</p>
<p>
自动登录: **<input type="checkbox" name="remember-me", id="remember-me" checked="checked"/>
</p>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
</div>
</body>
</html>
-----------------------------------------------------------------------------
CustomSecurityConfigurer中配置remember me,注入userDetailsService
// 设置remember me http.rememberMe().rememberMeParameter("remember-me").userDetailsService(customUserDetailsService).tokenValiditySeconds(300);
幻灯片 32
幻灯片 33
自定义logout页面,CustomLogoutSuccessHandler
/**
* Description
*
* @author chiliangxu
* @date 2018/12/25 12:59
*/
@Component
public class CustomLogoutSuccessHandler implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
CustomResponseBody customResponseBody = new CustomResponseBody();
customResponseBody.setStatus("05");
customResponseBody.setMsg("Logout Success");
httpServletResponse.getWriter().write(JSON.toJSONString(customResponseBody));
}
}
-------------------------------------------------------------------------------------
在CustomSecurityConfigurer中注入CustomLogoutSuccessHandler
@Configuration public class CustomSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
CustomAuthentlcationProvider customAuthentlcationProvider;
@Autowired
CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
@Autowired
CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
@Autowired
CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
@Autowired
CustomAccessDeniedHandler customAccessDeniedHandler;
@Autowired
CustomUserDetailsService customUserDetailsService;
@Autowired
CustomLogoutSuccessHandler customLogoutSuccessHandler;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthentlcationProvider);
// auth.inMemoryAuthentication().passwordEncoder(new CustomPasswordEncoder()).
// withUser("admin").password("admin").roles("ADMIN")
// .and()
// .withUser("clx").password("clx").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().authenticationEntryPoint(customAuthenticationEntryPoint)
.and()
.authorizeRequests()
.antMatchers("/**/webjars/**").permitAll()
.antMatchers("/**/swagger-ui.html").permitAll()
.antMatchers("/**/swagger-resources/**").permitAll()
.antMatchers("/**/swagger-ui/**").permitAll()
.antMatchers("/**/v2/api-docs").permitAll()
// 这种方式代码中会写死
// .antMatchers("/clxTest.html").hasRole("AAA")
.anyRequest() .access("@rbacservice.hasPermission(request, authentication)") // .authenticated() .and().formLogin().loginPage("/login") .successHandler(customAuthenticationSuccessHandler) .failureHandler(customAuthenticationFailureHandler) .permitAll() .and() .logout() .logoutSuccessHandler(customLogoutSuccessHandler) .permitAll() .and() .csrf().disable();
// 设置无权限访问内容
http.exceptionHandling().accessDeniedHandler(customAccessDeniedHandler);
// 设置remember me
http.rememberMe().rememberMeParameter("remember-me").userDetailsService(customUserDetailsService).tokenValiditySeconds(300);
}
}
幻灯片 34
现在貌似大多数网站用户认证都是基于 session 的,即在服务端生成用户相关的 session 数据,而发给客户端 sesssion_id 存放到 cookie 中,这样用客户端请求时带上 session_id 就可以验证服务器端是否存在 session 数据,以此完成用户认证。这种认证方式,可以更好的在服务端对会话进行控制,安全性比较高(session_id 随机),但是服务端需要存储 session 数据(如内存或数据库),这样无疑增加维护成本和减弱可扩展性(多台服务器)。 CSRF 攻击一般基于 cookie 。另外,如果是原生 app 使用这种服务接口,又因为没有浏览器 cookie 功能,所以接入会相对麻烦。
基于 token 的用户认证是一种服务端无状态的认证方式,服务端不用存放 token 数据。用户验证后,服务端生成一个 token(hash 或 encrypt)发给客户端,客户端可以放到 cookie 或 localStorage 中,每次请求时在 Header 中带上 token ,服务端收到 token 通过验证后即可确认用户身份。这种方式相对 cookie 的认证方式就简单一些,服务端不用存储认证数据,易维护扩展性强, token 存在 localStorage 可避免 CSRF , web 和 app 应用这用接口都比较简单。不过这种方式在加密或解密的时候会有一些性能开销(好像也不是很大),有些对称加密存在安全隐患(aes cbc 字节翻转攻击)。
幻灯片 35
幻灯片 36
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
--------------------------------------------------------
JwtTokenUtil
package com.clx.springbootdemoclx.config.security.utils;
import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
/**
* JwtTokenUtil
*
* @author chiliangxu
* @date 2018/12/25 15:10
*/
public class JwtTokenUtil {
/**
*
* Description:
*
* @param: [subject, expiration, salt] 用户名,过期时间(s),私钥
* @return: java.lang.String
* @auther: chiliangxu
* @date: 2018/12/25 15:19
*/
public static String generateToken(String subject, int expirationSeconds, String salt) {
return Jwts.builder()
.setClaims(null)
.setSubject(subject)
.setExpiration(new Date(System.currentTimeMillis() + expirationSeconds * 1000))
.signWith(SignatureAlgorithm.HS512, salt)
.compact();
}
/**
*
* Description:
*
* @param: [token, salt] token,私钥
* @return: java.lang.String
* @auther: chiliangxu
* @date: 2018/12/25 15:27
*/
public static String parseToken(String token, String salt) {
String subject = null;
try {
Claims claims = Jwts.parser().setSigningKey(salt).parseClaimsJws(token).getBody();
subject = claims.getSubject();
} catch(Exception e) {
}
return subject;
}
/**
*
* Description: Test
*
* @param: [args]
* @return: void
* @auther: chiliangxu
* @date: 2018/12/25 15:27
*/
public static void main(String[] args) {
String token = generateToken("clx", 10, "_secret");
String subject = parseToken(token, "_secret");
System.out.println(token);
System.out.println(subject);
}
}
幻灯片 37
JwtAuthenticationTokenFilter
package com.clx.springbootdemoclx.config.security;
import com.clx.springbootdemoclx.config.security.utils.JwtTokenUtil; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Component; 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;
/**
* Description
*
* @author chiliangxu
* @date 2018/12/25 15:44
*/
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
CustomUserDetailsService customUserDetailsService;
@Value("${jwt.header:#{null}}")
private String jwtHeader;
@Value("${jwt.secret:#{null}}")
private String jwtsecret;
@Value("${jwt.tokenHead:#{null}}")
private String jwtTokenHead;
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
// 可在yml中配置
String authHeader = httpServletRequest.getHeader(jwtHeader);
if (!StringUtils.isEmpty(authHeader) && authHeader.startsWith(jwtTokenHead + " ")) {
final String authToken = authHeader.substring((jwtTokenHead + " ").length());
String username = JwtTokenUtil.parseToken(authToken, jwtsecret);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);
if (userDetails != null) {
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
-----------------------------------------------------------------------------
CustomAuthenticationSuccessHandler
@Component public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Value("${jwt.expiration:#{null}}")
private int jwtExpirationSeconds;
@Value("${jwt.secret:#{null}}")
private String jwtsecret;
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
CustomResponseBody customResponseBody = new CustomResponseBody();
customResponseBody.setStatus("02");
customResponseBody.setMsg("Login success");
// 产生token
CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();
String token = JwtTokenUtil.generateToken(userDetails.getUsername(), jwtExpirationSeconds, jwtsecret);
customResponseBody.setToken(token);
httpServletResponse.getWriter().write(JSON.toJSONString(customResponseBody));
}
}
-----------------------------------------------------------------------------------------------------
CustomSecurityConfigurer
@Configuration public class CustomSecurityConfigurer extends WebSecurityConfigurerAdapter {
// @Autowired // CustomAuthentlcationProvider customAuthentlcationProvider;
@Autowired
CustomAuthenticationEntryPointHandler customAuthenticationEntryPointHandler;
@Autowired
CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
@Autowired
CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
@Autowired
CustomAccessDeniedHandler customAccessDeniedHandler;
@Autowired
CustomUserDetailsService customUserDetailsService;
@Autowired
CustomLogoutSuccessHandler customLogoutSuccessHandler;
@Autowired
JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// JWT时不用Provider方式
// auth.authenticationProvider(customAuthentlcationProvider);
// 这种加密算法每次产生结果都不一样,md5已经有点过时了
auth.userDetailsService(customUserDetailsService).passwordEncoder(new BCryptPasswordEncoder());
// auth.inMemoryAuthentication().passwordEncoder(new CustomPasswordEncoder()).
// withUser("admin").password("admin").roles("ADMIN")
// .and()
// .withUser("clx").password("clx").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.httpBasic().authenticationEntryPoint(customAuthenticationEntryPointHandler)
.and()
.authorizeRequests()
.antMatchers("/**/webjars/**").permitAll()
.antMatchers("/**/swagger-ui.html").permitAll()
.antMatchers("/**/swagger-resources/**").permitAll()
.antMatchers("/**/swagger-ui/**").permitAll()
.antMatchers("/**/v2/api-docs").permitAll()
// 这种方式代码中会写死
// .antMatchers("/clxTest.html").hasRole("AAA")
.anyRequest() .access("@rbacservice.hasPermission(request, authentication)") // .authenticated() .and().formLogin().loginPage("/login") .successHandler(customAuthenticationSuccessHandler) .failureHandler(customAuthenticationFailureHandler) .permitAll() .and() .logout() .logoutSuccessHandler(customLogoutSuccessHandler) .permitAll() .and() .csrf().disable();
// 设置无权限访问内容
http.exceptionHandling().accessDeniedHandler(customAccessDeniedHandler);
// 设置remember me
http.rememberMe().rememberMeParameter("remember-me").userDetailsService(customUserDetailsService).tokenValiditySeconds(300);
// 在默认fileter UsernamePasswordAuthenticationFilter执行前加入JwtTokenFilter
http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
// 禁用header缓存
http.headers().cacheControl();
}
}
幻灯片 38
JwtAuthenticationTokenFilter
package com.clx.springbootdemoclx.config.security;
import com.clx.springbootdemoclx.config.security.utils.JwtTokenUtil; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Component; 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;
/**
* Description
*
* @author chiliangxu
* @date 2018/12/25 15:44
*/
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
CustomUserDetailsService customUserDetailsService;
@Value("${jwt.header:#{null}}")
private String jwtHeader;
@Value("${jwt.secret:#{null}}")
private String jwtsecret;
@Value("${jwt.tokenHead:#{null}}")
private String jwtTokenHead;
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
// 可在yml中配置
String authHeader = httpServletRequest.getHeader(jwtHeader);
if (!StringUtils.isEmpty(authHeader) && authHeader.startsWith(jwtTokenHead + " ")) {
final String authToken = authHeader.substring((jwtTokenHead + " ").length());
String username = JwtTokenUtil.parseToken(authToken, jwtsecret);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);
if (userDetails != null) {
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
-----------------------------------------------------------------------------
CustomAuthenticationSuccessHandler
@Component public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Value("${jwt.expiration:#{null}}")
private int jwtExpirationSeconds;
@Value("${jwt.secret:#{null}}")
private String jwtsecret;
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
CustomResponseBody customResponseBody = new CustomResponseBody();
customResponseBody.setStatus("02");
customResponseBody.setMsg("Login success");
// 产生token
CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();
String token = JwtTokenUtil.generateToken(userDetails.getUsername(), jwtExpirationSeconds, jwtsecret);
customResponseBody.setToken(token);
httpServletResponse.getWriter().write(JSON.toJSONString(customResponseBody));
}
}
-----------------------------------------------------------------------------------------------------
CustomSecurityConfigurer
@Configuration public class CustomSecurityConfigurer extends WebSecurityConfigurerAdapter {
// @Autowired // CustomAuthentlcationProvider customAuthentlcationProvider;
@Autowired
CustomAuthenticationEntryPointHandler customAuthenticationEntryPointHandler;
@Autowired
CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
@Autowired
CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
@Autowired
CustomAccessDeniedHandler customAccessDeniedHandler;
@Autowired
CustomUserDetailsService customUserDetailsService;
@Autowired
CustomLogoutSuccessHandler customLogoutSuccessHandler;
@Autowired
JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// JWT时不用Provider方式
// auth.authenticationProvider(customAuthentlcationProvider);
// 这种加密算法每次产生结果都不一样,md5已经有点过时了
auth.userDetailsService(customUserDetailsService).passwordEncoder(new BCryptPasswordEncoder());
// auth.inMemoryAuthentication().passwordEncoder(new CustomPasswordEncoder()).
// withUser("admin").password("admin").roles("ADMIN")
// .and()
// .withUser("clx").password("clx").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.httpBasic().authenticationEntryPoint(customAuthenticationEntryPointHandler)
.and()
.authorizeRequests()
.antMatchers("/**/webjars/**").permitAll()
.antMatchers("/**/swagger-ui.html").permitAll()
.antMatchers("/**/swagger-resources/**").permitAll()
.antMatchers("/**/swagger-ui/**").permitAll()
.antMatchers("/**/v2/api-docs").permitAll()
// 这种方式代码中会写死
// .antMatchers("/clxTest.html").hasRole("AAA")
.anyRequest() .access("@rbacservice.hasPermission(request, authentication)") // .authenticated() .and().formLogin().loginPage("/login") .successHandler(customAuthenticationSuccessHandler) .failureHandler(customAuthenticationFailureHandler) .permitAll() .and() .logout() .logoutSuccessHandler(customLogoutSuccessHandler) .permitAll() .and() .csrf().disable();
// 设置无权限访问内容
http.exceptionHandling().accessDeniedHandler(customAccessDeniedHandler);
// 设置remember me
http.rememberMe().rememberMeParameter("remember-me").userDetailsService(customUserDetailsService).tokenValiditySeconds(300);
// 在默认fileter UsernamePasswordAuthenticationFilter执行前加入JwtTokenFilter
http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
// 禁用header缓存
http.headers().cacheControl();
}
}
幻灯片 39
JwtAuthenticationTokenFilter
package com.clx.springbootdemoclx.config.security;
import com.clx.springbootdemoclx.config.security.utils.JwtTokenUtil; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Component; 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;
/**
* Description
*
* @author chiliangxu
* @date 2018/12/25 15:44
*/
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
CustomUserDetailsService customUserDetailsService;
@Value("${jwt.header:#{null}}")
private String jwtHeader;
@Value("${jwt.secret:#{null}}")
private String jwtsecret;
@Value("${jwt.tokenHead:#{null}}")
private String jwtTokenHead;
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
// 可在yml中配置
String authHeader = httpServletRequest.getHeader(jwtHeader);
if (!StringUtils.isEmpty(authHeader) && authHeader.startsWith(jwtTokenHead + " ")) {
final String authToken = authHeader.substring((jwtTokenHead + " ").length());
String username = JwtTokenUtil.parseToken(authToken, jwtsecret);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);
if (userDetails != null) {
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
-----------------------------------------------------------------------------
CustomAuthenticationSuccessHandler
@Component public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Value("${jwt.expiration:#{null}}")
private int jwtExpirationSeconds;
@Value("${jwt.secret:#{null}}")
private String jwtsecret;
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
CustomResponseBody customResponseBody = new CustomResponseBody();
customResponseBody.setStatus("02");
customResponseBody.setMsg("Login success");
// 产生token
CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();
String token = JwtTokenUtil.generateToken(userDetails.getUsername(), jwtExpirationSeconds, jwtsecret);
customResponseBody.setToken(token);
httpServletResponse.getWriter().write(JSON.toJSONString(customResponseBody));
}
}
-----------------------------------------------------------------------------------------------------
CustomSecurityConfigurer
@Configuration public class CustomSecurityConfigurer extends WebSecurityConfigurerAdapter {
// @Autowired // CustomAuthentlcationProvider customAuthentlcationProvider;
@Autowired
CustomAuthenticationEntryPointHandler customAuthenticationEntryPointHandler;
@Autowired
CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
@Autowired
CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
@Autowired
CustomAccessDeniedHandler customAccessDeniedHandler;
@Autowired
CustomUserDetailsService customUserDetailsService;
@Autowired
CustomLogoutSuccessHandler customLogoutSuccessHandler;
@Autowired
JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// JWT时不用Provider方式
// auth.authenticationProvider(customAuthentlcationProvider);
// 这种加密算法每次产生结果都不一样,md5已经有点过时了
auth.userDetailsService(customUserDetailsService).passwordEncoder(new BCryptPasswordEncoder());
// auth.inMemoryAuthentication().passwordEncoder(new CustomPasswordEncoder()).
// withUser("admin").password("admin").roles("ADMIN")
// .and()
// .withUser("clx").password("clx").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.httpBasic().authenticationEntryPoint(customAuthenticationEntryPointHandler)
.and()
.authorizeRequests()
.antMatchers("/**/webjars/**").permitAll()
.antMatchers("/**/swagger-ui.html").permitAll()
.antMatchers("/**/swagger-resources/**").permitAll()
.antMatchers("/**/swagger-ui/**").permitAll()
.antMatchers("/**/v2/api-docs").permitAll()
// 这种方式代码中会写死
// .antMatchers("/clxTest.html").hasRole("AAA")
.anyRequest() .access("@rbacservice.hasPermission(request, authentication)") // .authenticated() .and().formLogin().loginPage("/login") .successHandler(customAuthenticationSuccessHandler) .failureHandler(customAuthenticationFailureHandler) .permitAll() .and() .logout() .logoutSuccessHandler(customLogoutSuccessHandler) .permitAll() .and() .csrf().disable();
// 设置无权限访问内容
http.exceptionHandling().accessDeniedHandler(customAccessDeniedHandler);
// 设置remember me
http.rememberMe().rememberMeParameter("remember-me").userDetailsService(customUserDetailsService).tokenValiditySeconds(300);
// 在默认fileter UsernamePasswordAuthenticationFilter执行前加入JwtTokenFilter
http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
// 禁用header缓存
http.headers().cacheControl();
}
}
幻灯片 40