日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

springsecurity实现自定义SecurityConfigurerAdapter、accessDeniedHandle.authenticationEntryPoint示例

發(fā)布時(shí)間:2024/9/30 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 springsecurity实现自定义SecurityConfigurerAdapter、accessDeniedHandle.authenticationEntryPoint示例 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • spring properties
  • 1.TokenUtil
  • 自定義 SecurityConfigurerAdapter
  • 自定義corsfilter
  • 自定義AuthenticationEntryPoint
  • 自定義AccessDeniedHandler
  • 匿名訪問(wèn)注解
  • springsecurity配置類

spring properties

@Data @Configuration(proxyBeanMethods = false) @ConfigurationProperties(prefix = "jwt") public class SecurityProperties {/** Request Headers : Authorization */private String header;/** 令牌前綴,最后留個(gè)空格 Bearer */private String tokenStartWith;/** 必須使用最少88位的Base64對(duì)該令牌進(jìn)行編碼 */private String base64Secret;private String secret;/** 令牌過(guò)期時(shí)間 此處單位/毫秒 */private Long tokenValidityInSeconds;/** 在線用戶 key,根據(jù) key 查詢 redis 中在線用戶的數(shù)據(jù) */private String onlineKey;/** 驗(yàn)證碼 key */private String codeKey;public String getTokenStartWith() {return tokenStartWith + " ";} }

1.TokenUtil

從token中獲取用戶信息、過(guò)期時(shí)驗(yàn)證token等的封裝

@Slf4j @Component public class TokenUtil {@Autowiredprivate SecurityProperties properties;/*** 權(quán)限緩存前綴*/private static final String REDIS_PREFIX_AUTH = "auth:";/*** 用戶信息緩存前綴*/private static final String REDIS_PREFIX_USER = "user-details:";/*** redis repository*/@Autowiredprivate RedisUtils redisUtils;/*** 獲取用戶名** @param token Token* @return String*/public String getUsernameFromToken(String token) {Claims claims = getClaimsFromToken(token);return claims != null ? claims.getSubject() : null;}/*** 獲取過(guò)期時(shí)間** @param token Token* @return Date*/public Date getExpiredFromToken(String token) {Claims claims = getClaimsFromToken(token);return claims != null ? claims.getExpiration() : null;}/*** 獲得 Claims** @param token Token* @return Claims*/private Claims getClaimsFromToken(String token) {Claims claims;try {claims = Jwts.parser().setSigningKey(properties.getSecret()).parseClaimsJws(token).getBody();} catch (Exception e) {log.warn("getClaimsFromToken exception", e);claims = null;}return claims;}/*** 計(jì)算過(guò)期時(shí)間** @return Date*/private Date generateExpired() {return new Date(System.currentTimeMillis() + properties.getTokenValidityInSeconds() * 1000);}/*** 判斷 Token 是否過(guò)期** @param token Token* @return Boolean*/private Boolean isTokenExpired(String token) {Date expirationDate = getExpiredFromToken(token);return expirationDate.before(new Date());}/*** 生成 Token** @param userDetails 用戶信息* @return String*/public String generateToken(UserDetails userDetails) {String secret=properties.getSecret();String token = Jwts.builder().setSubject(userDetails.getUsername()).setExpiration(generateExpired()).signWith(SignatureAlgorithm.HS512, secret).compact();String key = REDIS_PREFIX_AUTH + userDetails.getUsername() + ":" + token;redisUtils.set(key, token, properties.getTokenValidityInSeconds() / 1000);putUserDetails(userDetails);return token;}/*** 驗(yàn)證 Token** @param token Token* @return Boolean*/public Boolean validateToken(String token) {final String username = getUsernameFromToken(token);String key = REDIS_PREFIX_AUTH + username+ ":" + token;Object data = redisUtils.get(key);String redisToken = data == null ? null : data.toString();return StringUtils.isNotEmpty(token) && !isTokenExpired(token) && token.equals(redisToken);}/*** 移除 Token** @param token Token*/public void removeToken(String token) {final String username = getUsernameFromToken(token);String key = REDIS_PREFIX_AUTH + username+ ":" + token;redisUtils.del(key);delUserDetails(username);}/*** 獲得用戶信息 Json 字符串** @param token Token* @return String*/protected String getUserDetailsString(String token) {final String username = getUsernameFromToken(token);String key = REDIS_PREFIX_USER + username;Object data = redisUtils.get(key);return data == null ? null : data.toString();}/*** 獲得用戶信息** @param token Token* @return UserDetails*/public UserDetails getUserDetails(String token) {String userDetailsString = getUserDetailsString(token);if (userDetailsString != null) {return new Gson().fromJson(userDetailsString, JwtUser.class);}return null;}/*** 存儲(chǔ)用戶信息** @param userDetails 用戶信息*/private void putUserDetails(UserDetails userDetails) {String key = REDIS_PREFIX_USER + userDetails.getUsername();redisUtils.set(key, new Gson().toJson(userDetails), properties.getTokenValidityInSeconds() / 1000);}/*** 刪除用戶信息** @param username 用戶名*/private void delUserDetails(String username) {String key = REDIS_PREFIX_USER + username;redisUtils.del(key);}public String getToken(HttpServletRequest request) {final String requestHeader = request.getHeader(properties.getHeader());if (requestHeader != null && requestHeader.startsWith(properties.getTokenStartWith())) {return requestHeader.substring(7);}return null;}public static void main(String[] args) {String key = Base64.getEncoder().encodeToString("123".getBytes());Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFwcCIsIndyaXRlIl0sInVpbiI6MSwiZXhwIjoxNTc1MDE1ODgzLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiYjdiYjQ1NTQtNTQ4OS00YTg5LWI3NjQtNzNjODI0YzljNGMyIiwiY2xpZW50X2lkIjoibHZoYWliYW8ifQ.x7QZxRAR1wuX_YNLi6EzRJ1iaKr1rIEUgjtYF0oSx5k").getBody();System.out.println(JSON.toJSONString(claims));} }

其中生成token的方法將用戶信息也存在了redis中,在 validateToken方法中又從Redis中判斷響應(yīng)鍵是否存在,從而驗(yàn)證token‘

自定義 SecurityConfigurerAdapter

public class TokenConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {private final TokenUtil tokenUtil;public TokenConfigurer(TokenUtil tokenUtil){this.tokenUtil = tokenUtil;}@Overridepublic void configure(HttpSecurity http) {TokenFilter customFilter = new TokenFilter(tokenUtil);http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);} }

自定義corsfilter

@Configuration @EnableWebMvc public class ConfigurerAdapter implements WebMvcConfigurer {@Beanpublic CorsFilter corsFilter() {UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();CorsConfiguration config = new CorsConfiguration();// 允許cookies跨域config.setAllowCredentials(true);// #允許向該服務(wù)器提交請(qǐng)求的URI,*表示全部允許,在SpringMVC中,如果設(shè)成*,會(huì)自動(dòng)轉(zhuǎn)成當(dāng)前請(qǐng)求頭中的Originconfig.addAllowedOriginPattern("*");// #允許訪問(wèn)的頭信息,*表示全部config.addAllowedHeader("*");// 預(yù)檢請(qǐng)求的緩存時(shí)間(秒),即在這個(gè)時(shí)間段里,對(duì)于相同的跨域請(qǐng)求不會(huì)再預(yù)檢了config.setMaxAge(18000L);// 允許提交請(qǐng)求的方法類型,*表示全部允許config.addAllowedMethod("OPTIONS");config.addAllowedMethod("HEAD");config.addAllowedMethod("GET");config.addAllowedMethod("PUT");config.addAllowedMethod("POST");config.addAllowedMethod("DELETE");config.addAllowedMethod("PATCH");source.registerCorsConfiguration("/**", config);return new CorsFilter(source);}}

自定義AuthenticationEntryPoint

AuthenticationEntryPoint 用來(lái)解決匿名用戶訪問(wèn)無(wú)權(quán)限資源時(shí)的異常

@Component public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { //拓展AuthenticationEntryPoint接口啟動(dòng)身份驗(yàn)證方案。@Overridepublic void commence(HttpServletRequest request,HttpServletResponse response,AuthenticationException authException) throws IOException {// 當(dāng)用戶嘗試訪問(wèn)安全的REST資源而不提供任何憑據(jù)時(shí),將調(diào)用此方法發(fā)送401 響應(yīng)response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException == null ? "Unauthorized" : authException.getMessage());} }

自定義AccessDeniedHandler

AccessDeineHandler 用來(lái)解決認(rèn)證過(guò)的用戶訪問(wèn)無(wú)權(quán)限資源時(shí)的異常

@Component public class JwtAccessDeniedHandler implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {//當(dāng)用戶在沒(méi)有授權(quán)的情況下訪問(wèn)受保護(hù)的REST資源時(shí),將調(diào)用此方法發(fā)送403 Forbidden響應(yīng)response.sendError(HttpServletResponse.SC_FORBIDDEN, accessDeniedException.getMessage());} }

匿名訪問(wèn)注解

/*** 用于標(biāo)記匿名訪問(wèn)方法*/ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AnonymousAccess {}

使用:

/*** 訪問(wèn)首頁(yè)提示* @return /*/@GetMapping("/")@AnonymousAccesspublic String index() {return "Backend service started successfully";}

springsecurity配置類

@Configuration(proxyBeanMethods = false) @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowiredprivate TokenUtil tokenUtil;@Autowiredprivate CorsFilter corsFilter;@Autowiredprivate JwtAuthenticationEntryPoint authenticationErrorHandler;@Autowiredprivate JwtAccessDeniedHandler jwtAccessDeniedHandler;@Autowiredprivate ApplicationContext applicationContext;@BeanGrantedAuthorityDefaults grantedAuthorityDefaults() {// 去除 ROLE_ 前綴return new GrantedAuthorityDefaults("");}@Beanpublic PasswordEncoder passwordEncoder() {// 密碼加密方式return new BCryptPasswordEncoder();}@Overrideprotected void configure(HttpSecurity httpSecurity) throws Exception {// 搜尋匿名標(biāo)記 url: @AnonymousAccessMap<RequestMappingInfo, HandlerMethod> handlerMethodMap = applicationContext.getBean(RequestMappingHandlerMapping.class).getHandlerMethods();Set<String> anonymousUrls = new HashSet<>();for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) {HandlerMethod handlerMethod = infoEntry.getValue();AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);if (null != anonymousAccess) { //如果這個(gè)方法上面有@ AnonymousAccess則在anonymousUrls集合中加入anonymousUrls.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());}}httpSecurity// 禁用 CSRF.csrf().disable().addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)// 授權(quán)異常.exceptionHandling().authenticationEntryPoint(authenticationErrorHandler).accessDeniedHandler(jwtAccessDeniedHandler)// 防止iframe 造成跨域.and().headers().frameOptions().disable()// 不創(chuàng)建會(huì)話.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()// 靜態(tài)資源等等.antMatchers(HttpMethod.GET,"/*.html","/**/*.html","/**/*.css","/**/*.js","/webSocket/**").permitAll()// swagger 文檔.antMatchers("/swagger-ui.html").permitAll().antMatchers("/swagger-resources/**").permitAll().antMatchers("/webjars/**").permitAll().antMatchers("/*/api-docs").permitAll().antMatchers("/v2/api-docs-ext").permitAll()//.antMatchers("/api/wxmp/**").permitAll()// 文件.antMatchers("/avatar/**").permitAll().antMatchers("/file/**").permitAll()// 阿里巴巴 druid.antMatchers("/druid/**").permitAll().antMatchers("/api/canvas/**").permitAll()// 放行OPTIONS請(qǐng)求.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()// 自定義匿名訪問(wèn)所有url放行 : 允許匿名和帶權(quán)限以及登錄用戶訪問(wèn).antMatchers(anonymousUrls.toArray(new String[0])).permitAll()// 所有請(qǐng)求都需要認(rèn)證.anyRequest().authenticated().and().apply(securityConfigurerAdapter());//將SecurityConfigurerAdapter應(yīng)用于此SecurityBuilder并調(diào)用SecurityConfigurerAdapter.setBuilder(SecurityBuilder) 。}//apply方法:用于進(jìn)一步自定義的SecurityConfigurerAdapterprivate TokenConfigurer securityConfigurerAdapter() {return new TokenConfigurer(tokenUtil);} }

總結(jié)

以上是生活随笔為你收集整理的springsecurity实现自定义SecurityConfigurerAdapter、accessDeniedHandle.authenticationEntryPoint示例的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。