SpringBoot實戰電商項目mall(25k+star)地址: https://github.com/macrozheng/mall
學習過個人mall項目的應該知道,mall-admin
模塊是使用SpringSecurity+JWT來實現登陸認證的,而mall-portal
模塊是使用的SpringSecurity基於Session的默認機制來實現登錄認證的。不少小夥伴都找不到mall-portal
的登陸接口,最近我把這兩個模塊的登陸認證給統一了,都使用SpringSecurity+JWT的形式實現。
主要是經過把登陸認證的通用邏輯抽取到了mall-security
模塊來實現的,下面咱們講講如何使用mall-security
模塊來實現登陸認證,僅需四步便可。css
這裏咱們以
mall-portal
改造爲例來講說如何實現。
mall-security
依賴:<dependency> <groupId>com.macro.mall</groupId> <artifactId>mall-security</artifactId> </dependency>
mall-security
中的SecurityConfig配置,而且配置一個UserDetailsService接口的實現類,用於獲取登陸用戶詳情:/** * mall-security模塊相關配置 * Created by macro on 2019/11/5. */ @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled=true) public class MallSecurityConfig extends SecurityConfig { @Autowired private UmsMemberService memberService; @Bean public UserDetailsService userDetailsService() { //獲取登陸用戶信息 return username -> memberService.loadUserByUsername(username); } }
secure: ignored: urls: #安全路徑白名單 - /swagger-ui.html - /swagger-resources/** - /swagger/** - /**/v2/api-docs - /**/*.js - /**/*.css - /**/*.png - /**/*.ico - /webjars/springfox-swagger-ui/** - /druid/** - /actuator/** - /sso/** - /home/**
/** * 會員登陸註冊管理Controller * Created by macro on 2018/8/3. */ @Controller @Api(tags = "UmsMemberController", description = "會員登陸註冊管理") @RequestMapping("/sso") public class UmsMemberController { @Value("${jwt.tokenHeader}") private String tokenHeader; @Value("${jwt.tokenHead}") private String tokenHead; @Autowired private UmsMemberService memberService; @ApiOperation("會員登陸") @RequestMapping(value = "/login", method = RequestMethod.POST) @ResponseBody public CommonResult login(@RequestParam String username, @RequestParam String password) { String token = memberService.login(username, password); if (token == null) { return CommonResult.validateFailed("用戶名或密碼錯誤"); } Map<String, String> tokenMap = new HashMap<>(); tokenMap.put("token", token); tokenMap.put("tokenHead", tokenHead); return CommonResult.success(tokenMap); } @ApiOperation(value = "刷新token") @RequestMapping(value = "/refreshToken", method = RequestMethod.GET) @ResponseBody public CommonResult refreshToken(HttpServletRequest request) { String token = request.getHeader(tokenHeader); String refreshToken = memberService.refreshToken(token); if (refreshToken == null) { return CommonResult.failed("token已通過期!"); } Map<String, String> tokenMap = new HashMap<>(); tokenMap.put("token", refreshToken); tokenMap.put("tokenHead", tokenHead); return CommonResult.success(tokenMap); } }
將SpringSecurity+JWT的代碼封裝成通用模塊後,就能夠方便其餘須要登陸認證的模塊來使用,下面咱們來看看它是如何實現的,首先咱們看下
mall-security
的目錄結構。
mall-security ├── component | ├── JwtAuthenticationTokenFilter -- JWT登陸受權過濾器 | ├── RestAuthenticationEntryPoint -- 自定義返回結果:未登陸或登陸過時 | └── RestfulAccessDeniedHandler -- 自定義返回結果:沒有權限訪問時 ├── config | ├── IgnoreUrlsConfig -- 用於配置不須要安全保護的資源路徑 | └── SecurityConfig -- SpringSecurity通用配置 └── util └── JwtTokenUtil -- JWT的token處理工具類
其實我也就添加了兩個類,一個IgnoreUrlsConfig,用於從application.yml中獲取不須要安全保護的資源路徑。一個SecurityConfig提取了一些SpringSecurity的通用配置。
/** * 用於配置不須要保護的資源路徑 * Created by macro on 2018/11/5. */ @Getter @Setter @ConfigurationProperties(prefix = "secure.ignored") public class IgnoreUrlsConfig { private List<String> urls = new ArrayList<>(); }
/** * 對SpringSecurity的配置的擴展,支持自定義白名單資源路徑和查詢用戶邏輯 * Created by macro on 2019/11/5. */ public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity httpSecurity) throws Exception { ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity .authorizeRequests(); //不須要保護的資源路徑容許訪問 for (String url : ignoreUrlsConfig().getUrls()) { registry.antMatchers(url).permitAll(); } //容許跨域請求的OPTIONS請求 registry.antMatchers(HttpMethod.OPTIONS) .permitAll(); // 任何請求須要身份認證 registry.and() .authorizeRequests() .anyRequest() .authenticated() // 關閉跨站請求防禦及不使用session .and() .csrf() .disable() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 自定義權限拒絕處理類 .and() .exceptionHandling() .accessDeniedHandler(restfulAccessDeniedHandler()) .authenticationEntryPoint(restAuthenticationEntryPoint()) // 自定義權限攔截器JWT過濾器 .and() .addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService()) .passwordEncoder(passwordEncoder()); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() { return new JwtAuthenticationTokenFilter(); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Bean public RestfulAccessDeniedHandler restfulAccessDeniedHandler() { return new RestfulAccessDeniedHandler(); } @Bean public RestAuthenticationEntryPoint restAuthenticationEntryPoint() { return new RestAuthenticationEntryPoint(); } @Bean public IgnoreUrlsConfig ignoreUrlsConfig() { return new IgnoreUrlsConfig(); } @Bean public JwtTokenUtil jwtTokenUtil() { return new JwtTokenUtil(); } }
https://github.com/macrozheng/mallhtml
mall項目全套學習教程連載中,關注公衆號第一時間獲取。java