decurity-demo.sql 数据库验证的文件
image.png
密码是123或者123456/ 可以使用 new BCryptPasswordEncoder().encode(“123”);加密出来
模板项目地址https://gitee.com/find_me/java-findme

1.创建项目,引入依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-security</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-web</artifactId>
  8. </dependency>

引入依赖后,项目中所有的接口就会被保护起来,项目默认用户名未user,密码为启动后随即生成的,在控制台打印的密码

2.security的其他配置方式

  1. spring:
  2. security:
  3. user:
  4. name: find me
  5. password: 123456
  6. roles: admin

2.2基于内存

当然,开发者也可以自定义类继承自WebSecurityConfigurerAdapter ,进而实现对 Spring Security
更多的自定义配置,例如基于内存的认证,配置方式如下:

  1. @Configuration
  2. public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {
  3. // 密码不加密的配置 ,过时的方法
  4. @Bean
  5. //PasswordEncoder passwordEncoder () {
  6. //return NoOpPasswordEncoder. getlnstance () ;
  7. // }
  8. // 密码需要加密
  9. @Bean
  10. PasswordEncoder passwordEncoder() {
  11. return new BCryptPasswordEncoder();
  12. }
  13. //基于内存的配置
  14. @Override
  15. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  16. auth.inMemoryAuthentication()
  17. .withUser("javaboy").password("$2a$10$KlbLLUVVyvP0/vuhlabv0upg/ALdCrVEhUJOJDEND5ZtZJ.nGfVCm").roles("admin")
  18. .and()
  19. .withUser("江南一点雨").password("$2a$10$KlbLLUVVyvP0/vuhlabv0upg/ALdCrVEhUJOJDEND5ZtZJ.nGfVCm").roles("user");
  20. }

代码解释:
·自定义 MyWebSecurityConfig 继承自 WebSecurityConfigurerAdapter ,并重写configure(AuthenticationManagerBuilder auth)方法,在该方法中配直两个用户,一个用户名是
admin,密码123 ,具备两个角色 ADMIN USER 另一个用户名是 findme,密码是 123 ,具备一个角色USER
Spring Security 本是 0.6 Spring Security 中引入了 多种密码加密方式,开发者必须指定其中一种, NoOpPasswordEncoder ,即不对密码进行加密。

注意:基于配置和内存的方式在配置角色的时候不需要添加”ROLE_”.基于数据库的需要

2.3HttpSecurity(入门配置此文件)

根据实际情况进行角色配置

  1. @Configuration
  2. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  3. @Resource
  4. private ObjectMapper objectMapper;
  5. @Bean
  6. PasswordEncoder passwordEncoder() {
  7. return new BCryptPasswordEncoder();
  8. }
  9. // 配置登录的账号
  10. @Override
  11. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  12. auth.inMemoryAuthentication()
  13. .withUser("javaboy").password("$2a$10$KlbLLUVVyvP0/vuhlabv0upg/ALdCrVEhUJOJDEND5ZtZJ.nGfVCm").roles("admin")
  14. .and()
  15. .withUser("江南一点雨").password("$2a$10$KlbLLUVVyvP0/vuhlabv0upg/ALdCrVEhUJOJDEND5ZtZJ.nGfVCm").roles("user");
  16. }
  17. //基本的httpSecurity配置
  18. // 1.请求路径角色
  19. // 2.配置表单登录
  20. // 3.配置登录成功,失败或者登出的处理方式
  21. // authentication里面存放登录成功后的信息
  22. // {
  23. // "password": null, 密码
  24. // "username": "javaboy",
  25. // "authorities": [ 具备的角色
  26. // {
  27. // "authority": "ROLE_admin"
  28. // }
  29. // ],
  30. // "accountNonExpired": true, 账户没有过期,
  31. // "accountNonLocked": true, 账户没有锁定
  32. // "credentialsNonExpired": true, 密码没有过期
  33. // "enabled": true 账户可用
  34. // },
  35. @Override
  36. protected void configure(HttpSecurity http) throws Exception {
  37. http.authorizeRequests()//开启配置
  38. .antMatchers("/admin/**").hasRole("admin")//路径符合这个需要admin角色
  39. // .antMatchers("user/**").hasAnyRole("admin", "user")//路径符合这个,需要这两个的任意一个
  40. .antMatchers("/user/**").access("hasAnyRole('user','admin')")
  41. .anyRequest().authenticated()//其他请求,登录后就可以访问
  42. .and()
  43. .formLogin()//表单登录
  44. .loginProcessingUrl("/doLogin")//处理登录请求的地址
  45. .loginPage("/login")//配置登录页面(实际上还是一个请求地址) 前后端分类不存在这种页面 这里还是访问的应该请求,会根据这请求去返回登录页面
  46. .usernameParameter("uname")//修改登录的key
  47. .passwordParameter("passwd")//修改登录的key
  48. .successHandler(new AuthenticationSuccessHandler() { //登录成功的处理
  49. @Override// authentication保存了登录成功后的信息
  50. public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp,
  51. Authentication authentication) throws IOException, ServletException {
  52. resp.setContentType("application/json;charset=utf-8");
  53. PrintWriter out = resp.getWriter();
  54. Map<String, Object> map = new HashMap<>();
  55. map.put("status", 200);
  56. map.put("msg", authentication.getPrincipal());
  57. out.write(new ObjectMapper().writeValueAsString(map));
  58. out.flush();
  59. out.close();
  60. }
  61. })
  62. .failureHandler(new AuthenticationFailureHandler() {//登录失败的处理
  63. @Override // e登录失败的异常
  64. public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp,
  65. AuthenticationException e) throws IOException, ServletException {
  66. resp.setContentType("application/json;charset=utf-8");
  67. PrintWriter out = resp.getWriter();
  68. Map<String, Object> map = new HashMap<>();
  69. map.put("status", 401);
  70. if (e instanceof LockedException) {
  71. map.put("msg", "账户被锁定,登录失败!");
  72. } else if (e instanceof BadCredentialsException) {
  73. map.put("msg", "用户名或密码输入错误,登录失败!");
  74. } else if (e instanceof DisabledException) {
  75. map.put("msg", "账户被禁用,登录失败!");
  76. } else if (e instanceof AccountExpiredException) {
  77. map.put("msg", "账户过期,登录失败!");
  78. } else if (e instanceof CredentialsExpiredException) {
  79. map.put("msg", "密码过期,登录失败!");
  80. } else {
  81. map.put("msg", "登录失败!");
  82. }
  83. out.write(new ObjectMapper().writeValueAsString(map));
  84. out.flush();
  85. out.close();
  86. }
  87. })
  88. .permitAll()
  89. .and()
  90. .logout()
  91. .logoutUrl("/logout") //配置注销请求的地址
  92. .logoutSuccessHandler(new LogoutSuccessHandler() {//注销成功后的回调
  93. @Override
  94. public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp,
  95. Authentication authentication) throws IOException, ServletException {
  96. resp.setContentType("application/json;charset=utf-8");
  97. PrintWriter out = resp.getWriter();
  98. Map<String, Object> map = new HashMap<>();
  99. map.put("status", 200);
  100. map.put("msg", "注销登录成功!");
  101. out.write(new ObjectMapper().writeValueAsString(map));
  102. out.flush();
  103. out.close();
  104. }
  105. })
  106. .and()
  107. .csrf().disable();
  108. /**
  109. * 权限不足处理
  110. */
  111. http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {
  112. @Override
  113. public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException {
  114. httpServletResponse.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
  115. Map<String, Object> failureMap = new HashMap<>();
  116. failureMap.put("code", 403);
  117. failureMap.put("msg", "权限不足!");
  118. httpServletResponse.getWriter().println(objectMapper.writeValueAsString(failureMap));
  119. }
  120. });
  121. // /**
  122. // * 未登陆处理
  123. // */
  124. // http.exceptionHandling().authenticationEntryPoint(new AuthenticationEntryPoint() {
  125. // @Override
  126. // public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException {
  127. //
  128. //
  129. // httpServletResponse.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
  130. //
  131. // Map<String, Object> failureMap = new HashMap<>();
  132. // failureMap.put("code", 401);
  133. // failureMap.put("msg", "请先登录!");
  134. //
  135. // httpServletResponse.getWriter().println(objectMapper.writeValueAsString(failureMap));
  136. //
  137. // }
  138. // });
  139. }
  140. }

2.4多个HttpSecurity的配置(复杂业务场景下)—-security

参考项目 spring-security-me/security
采用静态内部类的方式 采用order设置优先级,数字越小,优先级越大

  1. @Configuration
  2. @EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true) //开启方法安全
  3. public class MultiHttpSecurityConfig {
  4. @Bean
  5. PasswordEncoder passwordEncoder() {
  6. return new BCryptPasswordEncoder();
  7. }
  8. @Autowired
  9. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  10. auth.inMemoryAuthentication()
  11. .withUser("javaboy").password("$2a$10$G3kVAJHvmRrr6sOj.j4xpO2Dsxl5EG8rHycPHFWyi9UMIhtdSH15u").roles("admin")
  12. .and()
  13. .withUser("江南一点雨").password("$2a$10$kWjG2GxWhm/2tN2ZBpi7bexXjUneIKFxIAaMYJzY7WcziZLCD4PZS").roles("user");
  14. }
  15. @Configuration
  16. @Order(1)
  17. public static class AdminSecurityConfig extends WebSecurityConfigurerAdapter{
  18. @Override
  19. protected void configure(HttpSecurity http) throws Exception {
  20. http.antMatcher("/admin/**").authorizeRequests().anyRequest().hasAnyRole("admin");
  21. //只有这种格式的路径才会去要求角色
  22. }
  23. }
  24. @Configuration
  25. public static class OtherSecurityConfig extends WebSecurityConfigurerAdapter{
  26. @Override
  27. protected void configure(HttpSecurity http) throws Exception {
  28. http.authorizeRequests().anyRequest().authenticated()
  29. .and()
  30. .formLogin()
  31. .loginProcessingUrl("/doLogin")
  32. .permitAll()
  33. .and()
  34. .csrf().disable();
  35. }
  36. }
  37. }

2.5配置方法安全

在Security上面加上

@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true) //开启方法安全 然后在方法上加PreAuthorize注解

  1. @Service
  2. public class MethodService {
  3. @PreAuthorize("hasRole('admin')")// 这个方法需要admin角色
  4. public String admin() {
  5. return "hello admin";
  6. }
  7. @Secured("ROLE_user") //需要user角色
  8. public String user() {
  9. return "hello user";
  10. }
  11. @PreAuthorize("hasAnyRole('admin','user')")//需要两者之一
  12. public String hello() {
  13. return "hello hello";
  14. }
  15. }

2.6基于数据库的认证(基础入门)——-sercuty-db/sercurity-dy

权限模型
权限模型.png
权限实际开发模型
权限实际开发模型.png

1.定义实体类user(继承UserDetails)和role

security-demo.sql

  1. /**
  2. * @Author 江南一点雨
  3. * UserDetails相当于一个规范
  4. * @Site www.javaboy.org 2019-08-11 17:08
  5. */
  6. public class User implements UserDetails {
  7. private Integer id;
  8. private String username;
  9. private String password;
  10. private Boolean enabled;
  11. private Boolean locked;
  12. private List<Role> roles;
  13. public List<Role> getRoles() {
  14. return roles;
  15. }
  16. public void setRoles(List<Role> roles) {
  17. this.roles = roles;
  18. }
  19. public Integer getId() {
  20. return id;
  21. }
  22. public void setId(Integer id) {
  23. this.id = id;
  24. }
  25. // 返回用户所有的角色
  26. @Override
  27. public Collection<? extends GrantedAuthority> getAuthorities() {
  28. List<SimpleGrantedAuthority> authorities = new ArrayList<>();
  29. // 重新整理一下 角色认证要以ROLE_开始 数据库没有就要在这里手动拼接
  30. for (Role role : roles) {
  31. authorities.add(new SimpleGrantedAuthority(role.getName()));
  32. }
  33. return authorities;
  34. }
  35. @Override
  36. public String getPassword() {
  37. return password;
  38. }
  39. public void setPassword(String password) {
  40. this.password = password;
  41. }
  42. @Override
  43. public String getUsername() {
  44. return username;
  45. }
  46. // 账户是否未过期 目前数据库没有就直说true
  47. @Override
  48. public boolean isAccountNonExpired() {
  49. return true;
  50. }
  51. // 账户是否未锁定
  52. @Override
  53. public boolean isAccountNonLocked() {
  54. return !locked;
  55. }
  56. // 密码是否未过期
  57. @Override
  58. public boolean isCredentialsNonExpired() {
  59. return true;
  60. }
  61. // 是否可用
  62. @Override
  63. public boolean isEnabled() {
  64. return enabled;
  65. }
  66. public void setUsername(String username) {
  67. this.username = username;
  68. }
  69. public void setEnabled(Boolean enabled) {
  70. this.enabled = enabled;
  71. }
  72. public void setLocked(Boolean locked) {
  73. this.locked = locked;
  74. }
  75. }

2.配置SecurityConfig

  1. /**
  2. * @Author 江南一点雨
  3. * @Site www.javaboy.org 2019-08-11 17:16
  4. */
  5. @Configuration
  6. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  7. @Autowired
  8. UserService userService;
  9. @Bean
  10. PasswordEncoder passwordEncoder() {
  11. return new BCryptPasswordEncoder();
  12. }
  13. // 此处去调用数据库的或者采用静态数据
  14. @Override
  15. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  16. auth.userDetailsService(userService);
  17. }
  18. @Override
  19. protected void configure(HttpSecurity http) throws Exception {
  20. //对于不同的路径要不同的角色 静态配置
  21. http.authorizeRequests()
  22. .antMatchers("/dba/**").hasRole("dba")
  23. .antMatchers("/admin/**").hasRole("admin")
  24. .antMatchers("/user/**").hasRole("user")
  25. .anyRequest().authenticated()
  26. .and()
  27. .formLogin()
  28. .permitAll()
  29. .and()
  30. .csrf().disable();
  31. }
  32. // 角色继承的bean
  33. @Bean
  34. RoleHierarchy roleHierarchy() {
  35. RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
  36. // 以前
  37. String hierarchy = "dba > admin admin > user";
  38. // 现在
  39. String hierarchy = "dba > admin \n admin > user";
  40. roleHierarchy.setHierarchy(hierarchy);
  41. return roleHierarchy;
  42. }

3.动态权限配置的Security写法

1. 1.先定义MyFilter实现FilterInvocationSecurityMetadataSource

主要就是分析出需要哪些角色

  1. /**
  2. * @Author 江南一点雨
  3. * @Site www.javaboy.org 2019-08-11 17:16
  4. */
  5. @Configuration
  6. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  7. @Autowired
  8. UserService userService;
  9. @Autowired
  10. MyFilter myFilter;
  11. @Autowired
  12. MyAccessDecisionManager myAccessDecisionManager;
  13. @Bean
  14. PasswordEncoder passwordEncoder() {
  15. return new BCryptPasswordEncoder();
  16. }
  17. @Override
  18. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  19. auth.userDetailsService(userService);
  20. }
  21. // @Bean
  22. // RoleHierarchy roleHierarchy() {
  23. // RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
  24. // String hierarchy = "dba > admin \n admin > user";
  25. // roleHierarchy.setHierarchy(hierarchy);
  26. // return roleHierarchy;
  27. // }
  28. @Bean
  29. @Override
  30. protected UserDetailsService userDetailsService() {
  31. return super.userDetailsService();
  32. }
  33. @Override
  34. protected void configure(HttpSecurity http) throws Exception {
  35. http.authorizeRequests()
  36. .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
  37. @Override
  38. public <O extends FilterSecurityInterceptor> O postProcess(O o) {
  39. o.setAccessDecisionManager(myAccessDecisionManager);
  40. o.setSecurityMetadataSource(myFilter);
  41. return o;
  42. }
  43. })
  44. .and()
  45. .formLogin()
  46. .permitAll()
  47. .and()
  48. .csrf().disable();
  49. }
  50. }

2.编写MyAccessDecisionManager继承 AccessDecisionManager

  1. /**
  2. * @Author 江南一点雨
  3. * @Site www.javaboy.org 2019-08-11 17:38
  4. */
  5. @Component
  6. public class MyAccessDecisionManager implements AccessDecisionManager {
  7. /**
  8. *
  9. * @param authentication 当前用户具备的角色
  10. * @param o
  11. * @param collection 当前路径需要的角色,这里是在MyFiter处理后得到的
  12. * @throws AccessDeniedException
  13. * @throws InsufficientAuthenticationException
  14. */
  15. @Override
  16. public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException {
  17. for (ConfigAttribute attribute : collection) {
  18. if ("ROLE_login".equals(attribute.getAttribute())) {
  19. // 如果是返回的ROLE_login说明你请求的路径不存在,所有判断你有没有登录 登录的就直接放行
  20. if (authentication instanceof AnonymousAuthenticationToken) {
  21. throw new AccessDeniedException("非法请求!");
  22. } else {
  23. return;
  24. }
  25. }
  26. // 获取我具备的角色
  27. Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
  28. // 做匹配
  29. for (GrantedAuthority authority : authorities) {
  30. if (authority.getAuthority().equals(attribute.getAttribute())) {
  31. return;
  32. }
  33. }
  34. }
  35. // 例如,我具备某些角色,但是此角色没有此路径的权限,那就是非要请求
  36. throw new AccessDeniedException("非法请求!");
  37. }
  38. @Override
  39. public boolean supports(ConfigAttribute configAttribute) {
  40. return true;
  41. }
  42. @Override
  43. public boolean supports(Class<?> aClass) {
  44. return true;
  45. }
  46. }

3.1SecurityConfig的写法
  1. /**
  2. * @Author 江南一点雨
  3. * @Site www.javaboy.org 2019-08-11 17:16
  4. */
  5. @Configuration
  6. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  7. @Autowired
  8. UserService userService;
  9. @Autowired
  10. MyFilter myFilter;
  11. @Autowired
  12. MyAccessDecisionManager myAccessDecisionManager;
  13. @Bean
  14. PasswordEncoder passwordEncoder() {
  15. return new BCryptPasswordEncoder();
  16. }
  17. @Override
  18. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  19. auth.userDetailsService(userService);
  20. }
  21. /
  22. @Override
  23. protected void configure(HttpSecurity http) throws Exception {
  24. http.authorizeRequests()
  25. .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {//FilterSecurityInterceptor 拦截器
  26. @Override
  27. public <O extends FilterSecurityInterceptor> O postProcess(O o) {
  28. o.setAccessDecisionManager(myAccessDecisionManager);
  29. o.setSecurityMetadataSource(myFilter);
  30. return o;
  31. }
  32. })
  33. .and()
  34. .formLogin()
  35. .permitAll()
  36. .and()
  37. .csrf().disable();
  38. }
  39. }

2.7spring security整合oauth2—-oauth2

2.7.1配置资源服务器 ResourceServerConfig

  1. /**
  2. * @Author 江南一点雨
  3. * @Site www.javaboy.org 2019-08-12 23:15
  4. * 资源服务器
  5. */
  6. @Configuration
  7. @EnableResourceServer
  8. public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
  9. @Override
  10. public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
  11. //指定资源id stateless配置基于令牌认证
  12. resources.resourceId("rid").stateless(true);
  13. }
  14. //此处角色路径可以从数据库加载
  15. // @Override
  16. // public void configure(HttpSecurity http) throws Exception {
  17. // // 路径的角色
  18. // http.authorizeRequests().antMatchers("/admin/**").hasRole("admin")
  19. // .antMatchers("/user/**").hasRole("user")
  20. // .anyRequest().authenticated();
  21. // }
  22. // 从数据库加载如下
  23. @Autowired
  24. MyFilter myFilter;
  25. @Autowired
  26. MyAccessDecisionManager myAccessDecisionManager;
  27. /**
  28. * @param http
  29. * @throws Exception
  30. */
  31. @Override
  32. public void configure(HttpSecurity http) throws Exception {
  33. http.authorizeRequests()
  34. .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
  35. @Override
  36. public <O extends FilterSecurityInterceptor> O postProcess(O o) {
  37. o.setAccessDecisionManager(myAccessDecisionManager);
  38. o.setSecurityMetadataSource(myFilter);
  39. return o;
  40. }
  41. })
  42. .and()
  43. .formLogin()
  44. .permitAll()
  45. .and()
  46. .csrf().disable();
  47. }
  48. }

2.7.2授权服务器 AuthorizationServerConfig

  1. /**
  2. * @Author 江南一点雨
  3. * @Site www.javaboy.org 2019-08-12 23:01
  4. * 授权服务器
  5. */
  6. @Configuration
  7. @EnableAuthorizationServer
  8. public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
  9. // 支持password的认证模式
  10. @Autowired
  11. AuthenticationManager authenticationManager;
  12. // 配置redis就会有
  13. @Autowired
  14. RedisConnectionFactory redisConnectionFactory;
  15. // 密码加密方式
  16. @Autowired
  17. UserDetailsService userDetailsService;
  18. @Bean
  19. PasswordEncoder passwordEncoder() {
  20. return new BCryptPasswordEncoder();
  21. }
  22. @Override
  23. public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
  24. //配置在内存中
  25. //配置认证模式
  26. //配置授权模式
  27. //资源id(名字)
  28. //配置的密码123456
  29. clients.inMemory()
  30. .withClient("password")
  31. .authorizedGrantTypes("password", "refresh_token")
  32. .accessTokenValiditySeconds(1800)
  33. .resourceIds("rid")
  34. .scopes("all")
  35. .secret("$2a$10$LcM2.fVWzB50vitKLrPPDugS/owlp.qVVT5jA0EyJuFeez6S5hTkm");
  36. }
  37. // 配置令牌的存储
  38. @Override
  39. public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
  40. endpoints.tokenStore(new RedisTokenStore(redisConnectionFactory)) //
  41. .authenticationManager(authenticationManager)
  42. .userDetailsService(userDetailsService);
  43. }
  44. @Override
  45. public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
  46. security.allowFormAuthenticationForClients();
  47. }
  48. }

2.7.3security配置文件

  1. @Override
  2. @Bean
  3. protected AuthenticationManager authenticationManager() throws Exception {
  4. return super.authenticationManager();
  5. }
  6. @Bean
  7. @Override
  8. protected UserDetailsService userDetailsService() {
  9. return super.userDetailsService();
  10. }
  11. // 静态的加载用户
  12. // @Override
  13. // protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  14. // auth.inMemoryAuthentication()
  15. // .withUser("javaboy").password("$2a$10$LcM2.fVWzB50vitKLrPPDugS/owlp.qVVT5jA0EyJuFeez6S5hTkm").roles("admin")
  16. // .and()
  17. // .withUser("江南一点雨")
  18. // .password("$2a$10$kwLIAqAupvY87OM.O25.Yu1QKEXV1imAv7jWbDaQRFUFWSnSiDEwG")
  19. // .roles("user");
  20. // }
  21. // 从数据库加载用户
  22. @Autowired
  23. UserService userService;
  24. @Override
  25. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  26. auth.userDetailsService(userService);
  27. }
  28. //放开oauth相关的请求,不就行拦截
  29. @Override
  30. protected void configure(HttpSecurity http) throws Exception {
  31. http.antMatcher("/oauth/**")
  32. .authorizeRequests()
  33. .antMatchers("/oauth/**").permitAll()
  34. .and().csrf().disable();
  35. }

2.7.4 MyFilter

  1. /**
  2. * @Author 江南一点雨
  3. * @Site www.javaboy.org 2019-08-11 17:24
  4. */
  5. @Component
  6. public class MyFilter implements FilterInvocationSecurityMetadataSource {
  7. // 做路径匹配的 提供了路径批评规则
  8. AntPathMatcher pathMatcher = new AntPathMatcher();
  9. @Autowired
  10. MenuService menuService;
  11. /**
  12. * 分析请求地址 根据请求的地址,分析出需要哪些角色
  13. * @param o
  14. * @return
  15. * @throws IllegalArgumentException
  16. */
  17. @Override
  18. public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
  19. // 请求的地址
  20. String requestUrl = ((FilterInvocation) o).getRequestUrl();
  21. // 所有的菜单 ,这里可以给一个缓存
  22. List<Menu> allMenus = menuService.getAllMenus();
  23. for (Menu menu : allMenus) {
  24. // 如果请求地址批评上了
  25. if (pathMatcher.match(menu.getPattern(), requestUrl)) {
  26. List<Role> roles = menu.getRoles();
  27. String[] rolesStr = new String[roles.size()];
  28. //查看需要哪些角色 rolesStr,防止角色集合
  29. for (int i = 0; i < roles.size(); i++) {
  30. rolesStr[i] = roles.get(i).getName();
  31. }
  32. return SecurityConfig.createList(rolesStr);
  33. }
  34. }
  35. // 没有匹配上路径,这个就是标识符号,看在数据库中没有这个路径,怎么处理
  36. return SecurityConfig.createList("ROLE_login");
  37. }
  38. @Override
  39. public Collection<ConfigAttribute> getAllConfigAttributes() {
  40. return null;
  41. }
  42. @Override
  43. public boolean supports(Class<?> aClass) {
  44. return true;
  45. }
  46. }

2.7.5 MyAccessDecisionManager

  1. /**
  2. * @Author 江南一点雨
  3. * @Site www.javaboy.org 2019-08-11 17:38
  4. */
  5. @Component
  6. public class MyAccessDecisionManager implements AccessDecisionManager {
  7. /**
  8. *
  9. * @param authentication 当前用户具备的角色
  10. * @param o
  11. * @param collection 当前路径需要的角色,这里是在MyFiter处理后得到的
  12. * @throws AccessDeniedException
  13. * @throws InsufficientAuthenticationException
  14. */
  15. @Override
  16. public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException {
  17. for (ConfigAttribute attribute : collection) {
  18. if ("ROLE_login".equals(attribute.getAttribute())) {
  19. // 如果是返回的ROLE_login说明你请求的路径不存在,所有判断你有没有登录 登录的就直接放行
  20. if (authentication instanceof AnonymousAuthenticationToken) {
  21. throw new AccessDeniedException("非法请求!");
  22. } else {
  23. return;
  24. }
  25. }
  26. // 获取我具备的角色
  27. Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
  28. // 做匹配
  29. for (GrantedAuthority authority : authorities) {
  30. if (authority.getAuthority().equals(attribute.getAttribute())) {
  31. return;
  32. }
  33. }
  34. }
  35. // 例如,我具备某些角色,但是此角色没有此路径的权限,那就是非要请求
  36. throw new AccessDeniedException("非法请求!");
  37. }
  38. @Override
  39. public boolean supports(ConfigAttribute configAttribute) {
  40. return true;
  41. }
  42. @Override
  43. public boolean supports(Class<?> aClass) {
  44. return true;
  45. }
  46. }

2.7.6 postman测试 -请求token

post http://127.0.0.1:8981/oauth/token Body x-www-form-urlencoded [{“key”:”username”,”value”:”admin”}, {“key”:”password”,”value”:”123”}, {“key”:”grant_type”,”value”:”password”}, {“key”:”client_id”,”value”:”password”}, {“key”:”scope”,”value”:”all”}, {“key”:”client_secret”,”value”:”123456”}]

  1. {
  2. "username":"admin",
  3. "password":"123",
  4. "grant_type":"password",
  5. "client_id":"password",
  6. "scope":"all",
  7. "client_secret":"123456",
  8. }

结果 { “access_token”: “d1bdfd01-e06a-4b4e-a661-a49012da9afa”, “token_type”: “bearer”, “refresh_token”: “d31082b6-68a7-46b5-937a-62a24b186970”, “expires_in”: 1325, “scope”: “all” }

换回新的token

  1. {
  2. "grant_type":"refresh_token",
  3. "refresh_token":"d31082b6-68a7-46b5-937a-62a24b186970",
  4. "grant_type":"password",
  5. "client_secret":"123456",
  6. }

2.8spring security支持json登录—-security-dy/security-db/oauth2

2.8.1重写UsernamePasswordAuthenticationFilter方法

  1. public class MyAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
  2. @Override
  3. public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws
  4. AuthenticationException {
  5. if (!request.getMethod().equals("POST")) {
  6. throw new AuthenticationServiceException(
  7. "Authentication method not supported: " + request.getMethod());
  8. }
  9. if (request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)) {
  10. //说明用户以 JSON 的形式传递的参数
  11. String username = null;
  12. String password = null;
  13. try {
  14. Map<String, String> map = new ObjectMapper().readValue(request.getInputStream(), Map.class);
  15. username = map.get("username");
  16. password = map.get("password");
  17. } catch (IOException e) {
  18. e.printStackTrace();
  19. }
  20. if (username == null) {
  21. username = "";
  22. }
  23. if (password == null) {
  24. password = "";
  25. }
  26. username = username.trim();
  27. UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
  28. username, password);
  29. // Allow subclasses to set the "details" property
  30. setDetails(request, authRequest);
  31. return this.getAuthenticationManager().authenticate(authRequest);
  32. }
  33. return super.attemptAuthentication(request, response);
  34. }

2.8.2注入重写的方法

在securityconfig中写入一下文件

  1. // 配置支持json登录
  2. @Bean
  3. MyAuthenticationFilter myAuthenticationFilter() throws Exception {
  4. MyAuthenticationFilter filter = new MyAuthenticationFilter();
  5. filter.setAuthenticationManager(authenticationManagerBean());
  6. return filter;
  7. }
  8. /**
  9. *
  10. * @param http
  11. * @throws Exception
  12. */
  13. @Override
  14. protected void configure(HttpSecurity http) throws Exception {
  15. http.addFilterAt(myAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
  16. }

2.8.3配置登录成功后的转跳和失败后转跳

在myAuthenticationFilter中配置
此时成功和失败的回调只能在fiter中配置,cnfigure中的配置是失效的

  1. // 配置支持json登录
  2. @Bean
  3. MyAuthenticationFilter myAuthenticationFilter() throws Exception {
  4. MyAuthenticationFilter filter = new MyAuthenticationFilter();
  5. filter.setAuthenticationManager(authenticationManagerBean());
  6. filter.setAuthenticationSuccessHandler(new AuthenticationSuccessHandler() { //登录成功的处理
  7. @Override// authentication保存了登录成功后的信息
  8. public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp,
  9. Authentication authentication) throws IOException, ServletException {
  10. resp.setContentType("application/json;charset=utf-8");
  11. PrintWriter out = resp.getWriter();
  12. Map<String, Object> map = new HashMap<>();
  13. map.put("status", 200);
  14. map.put("msg", authentication.getPrincipal());
  15. out.write(new ObjectMapper().writeValueAsString(map));
  16. out.flush();
  17. out.close();
  18. }
  19. });
  20. filter.setAuthenticationFailureHandler(new AuthenticationFailureHandler() {//登录失败的处理
  21. @Override // e登录失败的异常
  22. public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp,
  23. AuthenticationException e) throws IOException, ServletException {
  24. resp.setContentType("application/json;charset=utf-8");
  25. PrintWriter out = resp.getWriter();
  26. Map<String, Object> map = new HashMap<>();
  27. map.put("status", 401);
  28. if (e instanceof LockedException) {
  29. map.put("msg", "账户被锁定,登录失败!");
  30. } else if (e instanceof BadCredentialsException) {
  31. map.put("msg", "用户名或密码输入错误,登录失败!");
  32. } else if (e instanceof DisabledException) {
  33. map.put("msg", "账户被禁用,登录失败!");
  34. } else if (e instanceof AccountExpiredException) {
  35. map.put("msg", "账户过期,登录失败!");
  36. } else if (e instanceof CredentialsExpiredException) {
  37. map.put("msg", "密码过期,登录失败!");
  38. } else {
  39. map.put("msg", "登录失败!");
  40. }
  41. out.write(new ObjectMapper().writeValueAsString(map));
  42. out.flush();
  43. out.close();
  44. }
  45. });
  46. return filter;
  47. }

2.9spring security整合jwt —jwt-demo

2.9.1 JwtLoginFilter 登录的时候给用户token

  1. public class JwtLoginFilter extends AbstractAuthenticationProcessingFilter {
  2. // 实现构造方法
  3. /**
  4. *
  5. * @param defaultFilterProcessesUrl
  6. * @param authenticationManager
  7. */
  8. public JwtLoginFilter(String defaultFilterProcessesUrl, AuthenticationManager authenticationManager) {
  9. super(new AntPathRequestMatcher(defaultFilterProcessesUrl));
  10. setAuthenticationManager(authenticationManager);
  11. }
  12. /**
  13. * 提取用户名和密码去做登录
  14. *
  15. * @param req
  16. * @param httpServletResponse
  17. * @return
  18. * @throws AuthenticationException
  19. * @throws IOException
  20. */
  21. @Override
  22. public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse httpServletResponse)
  23. throws AuthenticationException, IOException {
  24. // 为了获取登录的数据转换成user
  25. User user = new ObjectMapper().readValue(req.getInputStream(), User.class);
  26. return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword()));
  27. }
  28. // 登录成功的回调 生成jwt
  29. @Override
  30. protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse resp,
  31. FilterChain chain, Authentication authResult) throws IOException, ServletException {
  32. Collection<? extends GrantedAuthority> authorities = authResult.getAuthorities();//获取登录用户的角色
  33. StringBuffer sb = new StringBuffer();
  34. for (GrantedAuthority authority : authorities) {
  35. //获取当前角色
  36. sb.append(authority.getAuthority()).append(",");
  37. }
  38. // 生成jwttoken
  39. String jwt = Jwts.builder()
  40. .claim("authorities", sb)// 用户的角色
  41. .setSubject(authResult.getName()) // 主题
  42. .setExpiration(new Date(System.currentTimeMillis() + 60 * 60 * 1000)) // 过期时间
  43. .signWith(SignatureAlgorithm.HS512, "findme") // 签名的算法
  44. .compact();
  45. Map<String, String> map = new HashMap<>();
  46. map.put("token", jwt);
  47. map.put("msg", "登录成功");
  48. resp.setContentType("application/json;charset=utf-8");
  49. PrintWriter out = resp.getWriter();
  50. out.write(new ObjectMapper().writeValueAsString(map));
  51. out.flush();
  52. out.close();
  53. }
  54. // 登录失败
  55. /**
  56. *
  57. *
  58. * @param req
  59. * @param resp
  60. * @param failed
  61. * @throws IOException
  62. * @throws ServletException 登录失败的异常,根据异常判断失败的原因
  63. */
  64. @Override
  65. protected void unsuccessfulAuthentication(HttpServletRequest req, HttpServletResponse resp,
  66. AuthenticationException failed) throws IOException, ServletException {
  67. Map<String, String> map = new HashMap<>();
  68. map.put("msg", "登录失败");
  69. resp.setContentType("application/json;charset=utf-8");
  70. PrintWriter out = resp.getWriter();
  71. out.write(new ObjectMapper().writeValueAsString(map));
  72. out.flush();
  73. out.close();
  74. }

2.9.2. 访问系统的时候效验token

  1. public class JwtFilter extends GenericFilterBean {
  2. /**
  3. * 用户每次登录的时候校验token
  4. *
  5. * @param servletRequest
  6. * @param servletResponse
  7. * @param filterChain
  8. * @throws IOException
  9. * @throws ServletException
  10. */
  11. @Override
  12. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
  13. FilterChain filterChain) throws IOException, ServletException {
  14. HttpServletRequest req = (HttpServletRequest) servletRequest;
  15. // token 放在很多地方都可以,此处是默认把token放到请求头中
  16. String jwtToken = req.getHeader("authorization");
  17. // 解析token
  18. Jws<Claims> jws = Jwts.parser().setSigningKey("findme") // 生成token的签名
  19. .parseClaimsJws(jwtToken.replace("Bearer", "")); // 前端的token会自动加一个Bearer,此处需要去掉
  20. Claims claims = jws.getBody(); // 登录的信息
  21. String username = claims.getSubject();// 用户名 刚才在生成的时候放入了
  22. // 拿到登录的角色后要转换成一个list集合解析 此处是当前用户的角色
  23. List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList((String) claims.get("authorities"));
  24. // new 一个新的token
  25. UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, null, authorities);
  26. SecurityContextHolder.getContext().setAuthentication(token);
  27. // 对过滤器放行
  28. filterChain.doFilter(servletRequest,servletResponse);
  29. }

2.9.3增加security的相关配置 configure(_HttpSecurity http) _

  1. // jwt 相关配置
  2. http.authorizeRequests()
  3. .antMatchers(HttpMethod.POST, "/login")
  4. .permitAll()
  5. .anyRequest().authenticated()
  6. .and()
  7. // 登录的过滤器
  8. .addFilterBefore(new JwtLoginFilter("/login", authenticationManager()), UsernamePasswordAuthenticationFilter.class)
  9. // 做校验的过滤器
  10. .addFilterBefore(new JwtFilter(), UsernamePasswordAuthenticationFilter.class)
  11. .csrf().disable();

2.10 oauth2 整合jwt+swagger —-swcurity-swagger/ 松哥例子swagger-jwt

注意在引入依赖的时候引入cloud相关的
E~7BT8XQEO722`7U6MEZIX3.png

2.10.1.AccessTokenConfig

  1. package com.find.securityswagger.auth;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.security.oauth2.provider.token.TokenStore;
  5. import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
  6. import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
  7. /**
  8. * @ClassName AccessTokenConfig
  9. * @Description token
  10. * @Author find me
  11. * @Date 2020/6/25 0025 20:37
  12. * @Version 1.0
  13. */
  14. @Configuration
  15. public class AccessTokenConfig {
  16. // TokenStore 我们使用 JwtTokenStore 这个实例。
  17. // 使用了 JWT,access_token 实际上就不用存储了(无状态登录,服务端不需要保存信息),
  18. // 因为用户的所有信息都在 jwt 里边,所以这里配置的 JwtTokenStore 本质上并不是做存储。
  19. @Bean
  20. TokenStore tokenStore() {
  21. return new JwtTokenStore(jwtAccessTokenConverter());
  22. }
  23. // 另外我们还提供了一个 JwtAccessTokenConverter,
  24. // 这个 JwtAccessTokenConverter 可以实现将用户信息和 JWT 进行转换(将用户信息转为 jwt 字符串,或者从 jwt 字符串提取出用户信息)。
  25. // 另外,在 JWT 字符串生成的时候,我们需要一个签名,这个签名需要自己保存好。
  26. @Bean
  27. JwtAccessTokenConverter jwtAccessTokenConverter() {
  28. JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
  29. converter.setSigningKey("findme");
  30. return converter;
  31. }
  32. }

2.10.2AuthorizationServer

  1. package com.find.securityswagger.auth;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.security.authentication.AuthenticationManager;
  6. import org.springframework.security.crypto.password.PasswordEncoder;
  7. import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
  8. import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
  9. import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
  10. import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
  11. import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
  12. import org.springframework.security.oauth2.provider.ClientDetailsService;
  13. import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
  14. import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
  15. import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
  16. import org.springframework.security.oauth2.provider.token.TokenStore;
  17. import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
  18. import java.util.Arrays;
  19. /**
  20. * @ClassName JwtAccessTokenConverter
  21. * @Description 将用户信息和 JWT 进行转换
  22. * @Author find me
  23. * @Date 2020/6/25 0025 20:39
  24. * @Version 1.0
  25. */
  26. @EnableAuthorizationServer
  27. @Configuration
  28. public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {
  29. @Autowired
  30. TokenStore tokenStore;
  31. @Autowired
  32. ClientDetailsService clientDetailsService;
  33. @Autowired
  34. AuthenticationManager authenticationManager;
  35. @Autowired
  36. PasswordEncoder passwordEncoder;
  37. @Autowired
  38. JwtAccessTokenConverter jwtAccessTokenConverter;
  39. //主要用来配置 Token 的一些基本信息,
  40. // 例如 Token 是否支持刷新、Token 的存储位置、Token 的有效期以及刷新 Token 的有效期等等。
  41. // Token 有效期这个好理解,刷新 Token 的有效期我说一下,
  42. // 当 Token 快要过期的时候,我们需要获取一个新的 Token,在获取新的 Token 时候,
  43. // 需要有一个凭证信息,这个凭证信息不是旧的 Token,而是另外一个 refresh_token,这个 refresh_token 也是有有效期的。
  44. @Bean
  45. AuthorizationServerTokenServices tokenServices() {
  46. DefaultTokenServices services = new DefaultTokenServices();
  47. services.setClientDetailsService(clientDetailsService);
  48. services.setSupportRefreshToken(true);
  49. services.setTokenStore(tokenStore);
  50. services.setAccessTokenValiditySeconds(60 * 60 * 24 * 2);
  51. services.setRefreshTokenValiditySeconds(60 * 60 * 24 * 7);
  52. TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
  53. tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter));
  54. services.setTokenEnhancer(tokenEnhancerChain);
  55. return services;
  56. }
  57. //用来配置令牌端点的安全约束,也就是这个端点谁能访问,谁不能访问。
  58. @Override
  59. public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
  60. security.allowFormAuthenticationForClients();
  61. }
  62. //用来配置客户端的详细信息
  63. @Override
  64. public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
  65. clients.inMemory()
  66. .withClient("findme")
  67. .secret(passwordEncoder.encode("123")) //
  68. .resourceIds("rid")//资源id
  69. .authorizedGrantTypes("password", "refresh_token")//授权类型
  70. .scopes("all")
  71. .redirectUris("http://localhost:6004/index.html");//重定向 uri
  72. }
  73. // 这里用来配置令牌的访问端点和令牌服务。
  74. @Override
  75. public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
  76. endpoints
  77. .authenticationManager(authenticationManager)
  78. .tokenServices(tokenServices());
  79. }
  80. }

2.10.3ResourceServerConfig

  1. package com.find.securityswagger.auth;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.security.config.annotation.ObjectPostProcessor;
  5. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  6. import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
  7. import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
  8. import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
  9. import org.springframework.security.oauth2.provider.token.TokenStore;
  10. import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
  11. /**
  12. * @ClassName ResourceServerConfig
  13. * @Description
  14. * @Author find me
  15. * @Date 2020/6/25 0025 20:41
  16. * @Version 1.0
  17. */
  18. @Configuration
  19. @EnableResourceServer
  20. public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
  21. @Autowired
  22. TokenStore tokenStore;
  23. //首先在 configure 方法中配置资源 ID 和 TokenStore,这里配置好之后,
  24. // 会自动调用 JwtAccessTokenConverter 将 jwt 解析出来,jwt 里边就
  25. // 包含了用户的基本信息,所以就不用远程校验 access_token 了。
  26. @Override
  27. public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
  28. //指定资源id stateless配置基于令牌认证
  29. // resources.resourceId("rid").stateless(true);
  30. resources.resourceId("rid").tokenStore(tokenStore);
  31. }
  32. @Autowired
  33. MyFilter myFilter;
  34. @Autowired
  35. MyAccessDecisionManager myAccessDecisionManager;
  36. /**
  37. * @param http
  38. * @throws Exception
  39. */
  40. @Override
  41. public void configure(HttpSecurity http) throws Exception {
  42. http.authorizeRequests()
  43. .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
  44. @Override
  45. public <O extends FilterSecurityInterceptor> O postProcess(O o) {
  46. o.setAccessDecisionManager(myAccessDecisionManager);
  47. o.setSecurityMetadataSource(myFilter);
  48. return o;
  49. }
  50. })
  51. .and()
  52. .formLogin()
  53. .permitAll()
  54. .and()
  55. .csrf().disable();
  56. }
  57. }

2.10.4 GlobalCorsConfiguration —-支持跨域

  1. package com.find.securityswagger.swaggerconfig;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.web.cors.CorsConfiguration;
  5. import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
  6. import org.springframework.web.filter.CorsFilter;
  7. /**
  8. * @ClassName GlobalCorsConfiguration
  9. * @Description 支持跨域
  10. * @Author find me
  11. * @Date 2020/6/25 0025 21:36
  12. * @Version 1.0
  13. */
  14. @Configuration
  15. public class GlobalCorsConfiguration {
  16. @Bean
  17. public CorsFilter corsFilter() {
  18. CorsConfiguration corsConfiguration = new CorsConfiguration();
  19. corsConfiguration.setAllowCredentials(true);
  20. corsConfiguration.addAllowedOrigin("*");
  21. corsConfiguration.addAllowedHeader("*");
  22. corsConfiguration.addAllowedMethod("*");
  23. UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
  24. urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
  25. return new CorsFilter(urlBasedCorsConfigurationSource);
  26. }
  27. }
  1. package com.find.securityswagger.swaggerconfig;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import springfox.documentation.builders.ApiInfoBuilder;
  5. import springfox.documentation.builders.OAuthBuilder;
  6. import springfox.documentation.builders.PathSelectors;
  7. import springfox.documentation.builders.RequestHandlerSelectors;
  8. import springfox.documentation.service.*;
  9. import springfox.documentation.spi.DocumentationType;
  10. import springfox.documentation.spi.service.contexts.SecurityContext;
  11. import springfox.documentation.spring.web.plugins.Docket;
  12. import springfox.documentation.swagger2.annotations.EnableSwagger2;
  13. import java.util.Arrays;
  14. import java.util.List;
  15. /**
  16. * @ClassName Swagger2Config
  17. * @Description swagger
  18. * @Author find me
  19. * @Date 2020/6/25 0025 21:19
  20. * @Version 1.0
  21. */
  22. @Configuration
  23. @EnableSwagger2
  24. public class Swagger2Config {
  25. // // 手动添加token的方式
  26. // @Bean
  27. // Docket docket() {
  28. // return new Docket(DocumentationType.SWAGGER_2)
  29. // .select()
  30. // .apis(RequestHandlerSelectors.basePackage("com.find.securityswagger.controller"))
  31. // .paths(PathSelectors.any())
  32. // .build()
  33. // .securityContexts(Arrays.asList(securityContexts()))
  34. // .securitySchemes(Arrays.asList(securitySchemes()))
  35. // .apiInfo(new ApiInfoBuilder()
  36. // .description("接口文档的描述信息")
  37. // .title("微人事项目接口文档")
  38. // .contact(new Contact("javaboy","https://www.yuque.com/findme","2354827879@qq.com"))
  39. // .version("v1.0")
  40. // .license("Apache2.0")
  41. // .build());
  42. // }
  43. // //通过 securitySchemes 来配置全局参数,这里的配置是一个名为 Authorization 的请求头(OAuth2 中需要携带的请求头)。
  44. // private SecurityScheme securitySchemes() {
  45. // return new ApiKey("Authorization", "Authorization", "header");
  46. // }
  47. //
  48. // // 则用来配置有哪些请求需要携带 Token,这里我们配置了所有请求。
  49. // private SecurityContext securityContexts() {
  50. // return SecurityContext.builder()
  51. // .securityReferences(defaultAuth())
  52. // .forPaths(PathSelectors.any())
  53. // .build();
  54. // }
  55. //
  56. // // 参数
  57. // private List<SecurityReference> defaultAuth() {
  58. // AuthorizationScope authorizationScope = new AuthorizationScope("xxx", "描述信息");
  59. // AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
  60. // authorizationScopes[0] = authorizationScope;
  61. // return Arrays.asList(new SecurityReference("Authorization", authorizationScopes));
  62. // }
  63. // 可以在页面去配置整个登录信息
  64. @Bean
  65. Docket docket() {
  66. return new Docket(DocumentationType.SWAGGER_2)
  67. .select()
  68. .apis(RequestHandlerSelectors.basePackage("com.find.securityswagger.controller"))
  69. .paths(PathSelectors.any())
  70. .build()
  71. .securityContexts(Arrays.asList(securityContext()))
  72. .securitySchemes(Arrays.asList(securityScheme()))
  73. .apiInfo(new ApiInfoBuilder()
  74. .description("接口文档的描述信息")
  75. .title("find me demo ")
  76. .contact(new Contact("findme","https://www.yuque.com/findme","2354827879@qq.com"))
  77. .version("v1.0")
  78. .license("Apache2.0")
  79. .build());
  80. }
  81. private AuthorizationScope[] scopes() {
  82. return new AuthorizationScope[]{
  83. new AuthorizationScope("all", "all scope")
  84. };
  85. }
  86. // 构建时即得配置 token 的获取地址。
  87. private SecurityScheme securityScheme() {
  88. GrantType grant = new ResourceOwnerPasswordCredentialsGrant("http://127.0.0.1:6004/oauth/token");
  89. return new OAuthBuilder().name("OAuth2")
  90. .grantTypes(Arrays.asList(grant))
  91. .scopes(Arrays.asList(scopes()))
  92. .build();
  93. }
  94. private SecurityContext securityContext() {
  95. return SecurityContext.builder()
  96. .securityReferences(Arrays.asList(new SecurityReference("OAuth2", scopes())))
  97. .forPaths(PathSelectors.any())
  98. .build();
  99. }
  100. }

swagger的两种配置的效果如下
1.spring security入门 - 图5
输入 Bearer ${token}
1.spring security入门 - 图6
postman测试参数如下 先获取token,在传递token
image.png
image.png

-1.configure其他配置

  1. // 配置不做拦截的地址
  2. @Override
  3. public void configure(WebSecurity web) throws Exception {
  4. // 返回login页就直接过,不用拦截
  5. web.ignoring().antMatchers("/login");
  6. web.ignoring().antMatchers("/swagger-ui.html")
  7. .antMatchers("/webjars/**")
  8. .antMatchers("/v2/**")
  9. .antMatchers("/swagger-resources/**");
  10. // web.ignoring().antMatchers("/css/**", "/js/**", "/index.html", "/img/**", "/fonts/**", "/favicon.ico", "/verifyCode");
  11. }
  12. @Override
  13. protected void configure(HttpSecurity http) throws Exception {
  14. http.authorizeRequests()//开启配置
  15. .antMatchers("/admin/**").hasRole("admin")//路径符合这个需要admin角色
  16. // .antMatchers("user/**").hasAnyRole("admin", "user")//路径符合这个,需要这两个的任意一个
  17. .antMatchers("/user/**").access("hasAnyRole('user','admin')")
  18. .anyRequest().authenticated()//其他请求,登录后就可以访问
  19. .and()
  20. .formLogin()//表单登录
  21. .loginProcessingUrl("/doLogin")//处理登录请求的地址
  22. .loginPage("/login")//配置登录页面(实际上还是一个请求地址) 前后端分类不存在这种页面 这里还是访问的应该请求,会根据这请求去返回登录页面
  23. .usernameParameter("uname")//修改登录的key
  24. .passwordParameter("passwd")//修改登录的key
  25. .successHandler(new AuthenticationSuccessHandler() { //登录成功的处理
  26. @Override// authentication保存了登录成功后的信息
  27. public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp,
  28. Authentication authentication) throws IOException, ServletException {
  29. resp.setContentType("application/json;charset=utf-8");
  30. PrintWriter out = resp.getWriter();
  31. Map<String, Object> map = new HashMap<>();
  32. map.put("status", 200);
  33. map.put("msg", authentication.getPrincipal());
  34. out.write(new ObjectMapper().writeValueAsString(map));
  35. out.flush();
  36. out.close();
  37. }
  38. })
  39. .failureHandler(new AuthenticationFailureHandler() {//登录失败的处理
  40. @Override // e登录失败的异常
  41. public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp,
  42. AuthenticationException e) throws IOException, ServletException {
  43. resp.setContentType("application/json;charset=utf-8");
  44. PrintWriter out = resp.getWriter();
  45. Map<String, Object> map = new HashMap<>();
  46. map.put("status", 401);
  47. if (e instanceof LockedException) {
  48. map.put("msg", "账户被锁定,登录失败!");
  49. } else if (e instanceof BadCredentialsException) {
  50. map.put("msg", "用户名或密码输入错误,登录失败!");
  51. } else if (e instanceof DisabledException) {
  52. map.put("msg", "账户被禁用,登录失败!");
  53. } else if (e instanceof AccountExpiredException) {
  54. map.put("msg", "账户过期,登录失败!");
  55. } else if (e instanceof CredentialsExpiredException) {
  56. map.put("msg", "密码过期,登录失败!");
  57. } else {
  58. map.put("msg", "登录失败!");
  59. }
  60. out.write(new ObjectMapper().writeValueAsString(map));
  61. out.flush();
  62. out.close();
  63. }
  64. })
  65. .permitAll()
  66. .and()
  67. .logout()
  68. .logoutUrl("/logout") //配置注销请求的地址
  69. .logoutSuccessHandler(new LogoutSuccessHandler() {//注销成功后的回调
  70. @Override
  71. public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp,
  72. Authentication authentication) throws IOException, ServletException {
  73. resp.setContentType("application/json;charset=utf-8");
  74. PrintWriter out = resp.getWriter();
  75. Map<String, Object> map = new HashMap<>();
  76. map.put("status", 200);
  77. map.put("msg", "注销登录成功!");
  78. out.write(new ObjectMapper().writeValueAsString(map));
  79. out.flush();
  80. out.close();
  81. }
  82. })
  83. .and()
  84. .csrf().disable();
  85. /**
  86. * 权限不足处理
  87. */
  88. http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {
  89. @Override
  90. public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException {
  91. httpServletResponse.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
  92. Map<String, Object> failureMap = new HashMap<>();
  93. failureMap.put("code", 403);
  94. failureMap.put("msg", "权限不足!");
  95. httpServletResponse.getWriter().println(objectMapper.writeValueAsString(failureMap));
  96. }
  97. });
  98. // /**
  99. // * 未登陆处理
  100. // */
  101. // http.exceptionHandling().authenticationEntryPoint(new AuthenticationEntryPoint() {
  102. // @Override
  103. // public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException {
  104. //
  105. //
  106. // httpServletResponse.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
  107. //
  108. // Map<String, Object> failureMap = new HashMap<>();
  109. // failureMap.put("code", 401);
  110. // failureMap.put("msg", "请先登录!");
  111. //
  112. // httpServletResponse.getWriter().println(objectMapper.writeValueAsString(failureMap));
  113. //
  114. // }
  115. // });
  116. //