文章目录

  • 1.spring security入门
    • 1.创建项目,引入依赖
    • 2.security的其他配置方式
      • 2.2基于内存
      • 2.3HttpSecurity(入门配置此文件)
      • 2.4多个HttpSecurity的配置(复杂业务场景下)---security
      • 2.5配置方法安全
      • 2.6基于数据库的认证(基础入门)-----sercuty-db/sercurity-dy
        • 1.定义实体类user(继承UserDetails)和role
        • 2.配置SecurityConfig
        • 3.动态权限配置的Security写法
          • 1. 1.先定义MyFilter实现FilterInvocationSecurityMetadataSource
          • 3.1SecurityConfig的写法
      • 2.7spring security整合oauth2---oauth2
        • 2.7.1配置资源服务器 ResourceServerConfig
        • 2.7.2授权服务器 AuthorizationServerConfig
        • 2.7.3security配置文件
        • 2.7.4 MyFilter
        • 2.7.5 MyAccessDecisionManager
        • 2.7.6 postman测试 -请求token
      • 2.8spring security支持json登录---security-dy/security-db/oauth2
        • 2.8.1重写UsernamePasswordAuthenticationFilter方法
        • 2.8.2注入重写的方法
        • 2.8.3配置登录成功后的转跳和失败后转跳
      • 2.9spring security整合jwt --jwt-demo
        • 2.9.1 JwtLoginFilter _登录的时候给用户token_
        • 2.9.2. _访问系统的时候效验token_
        • 2.9.3增加security的相关配置 configure_(_HttpSecurity http_) _
      • 2.10 oauth2 整合jwt+swagger ---swcurity-swagger/ 松哥例子swagger-jwt
        • 2.10.1.AccessTokenConfig
        • 2.10.2AuthorizationServer
        • 2.10.3ResourceServerConfig
        • 2.10.4 GlobalCorsConfiguration ---支持跨域
      • 2.11configure其他配置

1.spring security入门

decurity-demo.sql 数据库验证的文件

密码是123或者123456/ 可以使用 new BCryptPasswordEncoder_().encode(“123”)_;加密出来
模板项目地址https://gitee.com/find_me/java-findme

1.创建项目,引入依赖

  <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>

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

2.security的其他配置方式

spring:security:user: name: find mepassword: 123456roles: admin

2.2基于内存

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

@Configuration public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter { // 密码不加密的配置 ,过时的方法@Bean //PasswordEncoder passwordEncoder () { //return NoOpPasswordEncoder. getlnstance () ; // }// 密码需要加密@BeanPasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}//基于内存的配置@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().withUser("javaboy").password("$2a$10$KlbLLUVVyvP0/vuhlabv0upg/ALdCrVEhUJOJDEND5ZtZJ.nGfVCm").roles("admin").and().withUser("findme").password("$2a$10$KlbLLUVVyvP0/vuhlabv0upg/ALdCrVEhUJOJDEND5ZtZJ.nGfVCm").roles("user");}

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

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

2.3HttpSecurity(入门配置此文件)

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

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Resourceprivate ObjectMapper objectMapper;@BeanPasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}// 配置登录的账号@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().withUser("javaboy").password("$2a$10$KlbLLUVVyvP0/vuhlabv0upg/ALdCrVEhUJOJDEND5ZtZJ.nGfVCm").roles("admin").and().withUser("findme").password("$2a$10$KlbLLUVVyvP0/vuhlabv0upg/ALdCrVEhUJOJDEND5ZtZJ.nGfVCm").roles("user");}//基本的httpSecurity配置// 1.请求路径角色// 2.配置表单登录// 3.配置登录成功,失败或者登出的处理方式// authentication里面存放登录成功后的信息//      {//            "password": null, 密码//             "username": "javaboy",//             "authorities": [ 具备的角色//            {//                "authority": "ROLE_admin" //            }//        ],//            "accountNonExpired": true, 账户没有过期,//                "accountNonLocked": true, 账户没有锁定//                "credentialsNonExpired": true, 密码没有过期//                "enabled": true 账户可用//        },@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests()//开启配置.antMatchers("/admin/**").hasRole("admin")//路径符合这个需要admin角色
//                .antMatchers("user/**").hasAnyRole("admin", "user")//路径符合这个,需要这两个的任意一个.antMatchers("/user/**").access("hasAnyRole('user','admin')").anyRequest().authenticated()//其他请求,登录后就可以访问.and().formLogin()//表单登录.loginProcessingUrl("/doLogin")//处理登录请求的地址.loginPage("/login")//配置登录页面(实际上还是一个请求地址) 前后端分类不存在这种页面 这里还是访问的应该请求,会根据这请求去返回登录页面.usernameParameter("uname")//修改登录的key.passwordParameter("passwd")//修改登录的key.successHandler(new AuthenticationSuccessHandler() { //登录成功的处理@Override// authentication保存了登录成功后的信息public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp,Authentication authentication) throws IOException, ServletException {resp.setContentType("application/json;charset=utf-8");PrintWriter out = resp.getWriter();Map<String, Object> map = new HashMap<>();map.put("status", 200);map.put("msg", authentication.getPrincipal());out.write(new ObjectMapper().writeValueAsString(map));out.flush();out.close();}}).failureHandler(new AuthenticationFailureHandler() {//登录失败的处理@Override // e登录失败的异常public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp,AuthenticationException e) throws IOException, ServletException {resp.setContentType("application/json;charset=utf-8");PrintWriter out = resp.getWriter();Map<String, Object> map = new HashMap<>();map.put("status", 401);if (e instanceof LockedException) {map.put("msg", "账户被锁定,登录失败!");} else if (e instanceof BadCredentialsException) {map.put("msg", "用户名或密码输入错误,登录失败!");} else if (e instanceof DisabledException) {map.put("msg", "账户被禁用,登录失败!");} else if (e instanceof AccountExpiredException) {map.put("msg", "账户过期,登录失败!");} else if (e instanceof CredentialsExpiredException) {map.put("msg", "密码过期,登录失败!");} else {map.put("msg", "登录失败!");}out.write(new ObjectMapper().writeValueAsString(map));out.flush();out.close();}}).permitAll().and().logout().logoutUrl("/logout") //配置注销请求的地址.logoutSuccessHandler(new LogoutSuccessHandler() {//注销成功后的回调@Overridepublic void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp,Authentication authentication) throws IOException, ServletException {resp.setContentType("application/json;charset=utf-8");PrintWriter out = resp.getWriter();Map<String, Object> map = new HashMap<>();map.put("status", 200);map.put("msg", "注销登录成功!");out.write(new ObjectMapper().writeValueAsString(map));out.flush();out.close();}}).and().csrf().disable();/*** 权限不足处理*/http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {@Overridepublic void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException {httpServletResponse.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);Map<String, Object> failureMap = new HashMap<>();failureMap.put("code", 403);failureMap.put("msg", "权限不足!");httpServletResponse.getWriter().println(objectMapper.writeValueAsString(failureMap));}});
//        /**
//         * 未登陆处理
//         */
//        http.exceptionHandling().authenticationEntryPoint(new AuthenticationEntryPoint() {//            @Override
//            public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException {//
//
//                httpServletResponse.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
//
//                Map<String, Object> failureMap = new HashMap<>();
//                failureMap.put("code", 401);
//                failureMap.put("msg", "请先登录!");
//
//                httpServletResponse.getWriter().println(objectMapper.writeValueAsString(failureMap));
//
//            }
//        });}
}

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

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

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true) //开启方法安全
public class MultiHttpSecurityConfig {@BeanPasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Autowiredprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().withUser("javaboy").password("$2a$10$G3kVAJHvmRrr6sOj.j4xpO2Dsxl5EG8rHycPHFWyi9UMIhtdSH15u").roles("admin").and().withUser("").password("$2a$10$kWjG2GxWhm/2tN2ZBpi7bexXjUneIKFxIAaMYJzY7WcziZLCD4PZS").roles("user");}@Configuration@Order(1)public static class AdminSecurityConfig extends WebSecurityConfigurerAdapter{@Overrideprotected void configure(HttpSecurity http) throws Exception {http.antMatcher("/admin/**").authorizeRequests().anyRequest().hasAnyRole("admin");//只有这种格式的路径才会去要求角色}}@Configurationpublic static class OtherSecurityConfig extends WebSecurityConfigurerAdapter{@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().formLogin().loginProcessingUrl("/doLogin").permitAll().and().csrf().disable();}}
}

2.5配置方法安全

在Security上面加上

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

@Service
public class MethodService {@PreAuthorize("hasRole('admin')")// 这个方法需要admin角色public String admin() {return "hello admin";}@Secured("ROLE_user")  //需要user角色public String user() {return "hello user";}@PreAuthorize("hasAnyRole('admin','user')")//需要两者之一public String hello() {return "hello hello";}
}

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

权限模型

权限实际开发模型

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

security-demo.sql


public class User implements UserDetails {private Integer id;private String username;private String password;private Boolean enabled;private Boolean locked;private List<Role> roles;public List<Role> getRoles() {return roles;}public void setRoles(List<Role> roles) {this.roles = roles;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}// 返回用户所有的角色@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {List<SimpleGrantedAuthority> authorities = new ArrayList<>();// 重新整理一下 角色认证要以ROLE_开始 数据库没有就要在这里手动拼接for (Role role : roles) {authorities.add(new SimpleGrantedAuthority(role.getName()));}return authorities;}@Overridepublic String getPassword() {return password;}public void setPassword(String password) {this.password = password;}@Overridepublic String getUsername() {return username;}// 账户是否未过期 目前数据库没有就直说true@Overridepublic boolean isAccountNonExpired() {return true;}// 账户是否未锁定@Overridepublic boolean isAccountNonLocked() {return !locked;}// 密码是否未过期@Overridepublic boolean isCredentialsNonExpired() {return true;}// 是否可用@Overridepublic boolean isEnabled() {return enabled;}public void setUsername(String username) {this.username = username;}public void setEnabled(Boolean enabled) {this.enabled = enabled;}public void setLocked(Boolean locked) {this.locked = locked;}
}

2.配置SecurityConfig

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@AutowiredUserService userService;@BeanPasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}// 此处去调用数据库的或者采用静态数据@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userService);}@Overrideprotected void configure(HttpSecurity http) throws Exception {//对于不同的路径要不同的角色 静态配置http.authorizeRequests().antMatchers("/dba/**").hasRole("dba").antMatchers("/admin/**").hasRole("admin").antMatchers("/user/**").hasRole("user").anyRequest().authenticated().and().formLogin().permitAll().and().csrf().disable();}// 角色继承的bean@BeanRoleHierarchy roleHierarchy() {RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();// 以前String hierarchy = "dba > admin admin > user";// 现在String hierarchy = "dba > admin \n admin > user";roleHierarchy.setHierarchy(hierarchy);return roleHierarchy;}

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

1. 1.先定义MyFilter实现FilterInvocationSecurityMetadataSource

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

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@AutowiredUserService userService;@AutowiredMyFilter myFilter;@AutowiredMyAccessDecisionManager myAccessDecisionManager;@BeanPasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userService);}//    @Bean
//    RoleHierarchy roleHierarchy() {//        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
//        String hierarchy = "dba > admin \n admin > user";
//        roleHierarchy.setHierarchy(hierarchy);
//        return roleHierarchy;
//    }
@Bean
@Override
protected UserDetailsService userDetailsService() {return super.userDetailsService();
}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {@Overridepublic <O extends FilterSecurityInterceptor> O postProcess(O o) {o.setAccessDecisionManager(myAccessDecisionManager);o.setSecurityMetadataSource(myFilter);return o;}}).and().formLogin().permitAll().and().csrf().disable();}
}

2.编写MyAccessDecisionManager继承 AccessDecisionManager


@Component
public class MyAccessDecisionManager implements AccessDecisionManager {/**** @param authentication 当前用户具备的角色* @param o* @param collection  当前路径需要的角色,这里是在MyFiter处理后得到的* @throws AccessDeniedException* @throws InsufficientAuthenticationException*/@Overridepublic void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException {for (ConfigAttribute attribute : collection) {if ("ROLE_login".equals(attribute.getAttribute())) {// 如果是返回的ROLE_login说明你请求的路径不存在,所有判断你有没有登录 登录的就直接放行if (authentication instanceof AnonymousAuthenticationToken) {throw new AccessDeniedException("非法请求!");} else {return;}}// 获取我具备的角色Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();// 做匹配for (GrantedAuthority authority : authorities) {if (authority.getAuthority().equals(attribute.getAttribute())) {return;}}}// 例如,我具备某些角色,但是此角色没有此路径的权限,那就是非要请求throw new AccessDeniedException("非法请求!");}@Overridepublic boolean supports(ConfigAttribute configAttribute) {return true;}@Overridepublic boolean supports(Class<?> aClass) {return true;}
}
3.1SecurityConfig的写法

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@AutowiredUserService userService;@AutowiredMyFilter myFilter;@AutowiredMyAccessDecisionManager myAccessDecisionManager;@BeanPasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userService);}/@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {//FilterSecurityInterceptor 拦截器@Overridepublic <O extends FilterSecurityInterceptor> O postProcess(O o) {o.setAccessDecisionManager(myAccessDecisionManager);o.setSecurityMetadataSource(myFilter);return o;}}).and().formLogin().permitAll().and().csrf().disable();}
}

2.7spring security整合oauth2—oauth2

2.7.1配置资源服务器 ResourceServerConfig

/*** 资源服务器*/
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {@Overridepublic void configure(ResourceServerSecurityConfigurer resources) throws Exception {//指定资源id stateless配置基于令牌认证resources.resourceId("rid").stateless(true);}//此处角色路径可以从数据库加载//    @Override
//    public void configure(HttpSecurity http) throws Exception {//        // 路径的角色
//        http.authorizeRequests().antMatchers("/admin/**").hasRole("admin")
//                .antMatchers("/user/**").hasRole("user")
//                .anyRequest().authenticated();
//    }// 从数据库加载如下@AutowiredMyFilter myFilter;@AutowiredMyAccessDecisionManager myAccessDecisionManager;/*** @param http* @throws Exception*/@Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests().withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {@Overridepublic <O extends FilterSecurityInterceptor> O postProcess(O o) {o.setAccessDecisionManager(myAccessDecisionManager);o.setSecurityMetadataSource(myFilter);return o;}}).and().formLogin().permitAll().and().csrf().disable();}}

2.7.2授权服务器 AuthorizationServerConfig


/*** 授权服务器*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {// 支持password的认证模式@AutowiredAuthenticationManager authenticationManager;// 配置redis就会有@AutowiredRedisConnectionFactory redisConnectionFactory;// 密码加密方式@AutowiredUserDetailsService userDetailsService;@BeanPasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {//配置在内存中//配置认证模式//配置授权模式//资源id(名字)//配置的密码123456clients.inMemory().withClient("password").authorizedGrantTypes("password", "refresh_token").accessTokenValiditySeconds(1800).resourceIds("rid").scopes("all").secret("$2a$10$LcM2.fVWzB50vitKLrPPDugS/owlp.qVVT5jA0EyJuFeez6S5hTkm");}// 配置令牌的存储@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.tokenStore(new RedisTokenStore(redisConnectionFactory)) //.authenticationManager(authenticationManager).userDetailsService(userDetailsService);}@Overridepublic void configure(AuthorizationServerSecurityConfigurer security) throws Exception {security.allowFormAuthenticationForClients();}}

2.7.3security配置文件

@Override@Beanprotected AuthenticationManager authenticationManager() throws Exception {return super.authenticationManager();}@Bean@Overrideprotected UserDetailsService userDetailsService() {return super.userDetailsService();}//  静态的加载用户
//    @Override
//    protected void configure(AuthenticationManagerBuilder auth) throws Exception {//        auth.inMemoryAuthentication()
//                .withUser("javaboy").password("$2a$10$LcM2.fVWzB50vitKLrPPDugS/owlp.qVVT5jA0EyJuFeez6S5hTkm").roles("admin")
//                .and()
//                .withUser("finde")
//                .password("$2a$10$kwLIAqAupvY87OM.O25.Yu1QKEXV1imAv7jWbDaQRFUFWSnSiDEwG")
//                .roles("user");
//    }
// 从数据库加载用户@AutowiredUserService userService;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userService);}//放开oauth相关的请求,不就行拦截@Overrideprotected void configure(HttpSecurity http) throws Exception {http.antMatcher("/oauth/**").authorizeRequests().antMatchers("/oauth/**").permitAll().and().csrf().disable();}

2.7.4 MyFilter

@Component
public class MyFilter implements FilterInvocationSecurityMetadataSource {// 做路径匹配的 提供了路径批评规则AntPathMatcher pathMatcher = new AntPathMatcher();@AutowiredMenuService menuService;/*** 分析请求地址 根据请求的地址,分析出需要哪些角色* @param o* @return* @throws IllegalArgumentException*/@Overridepublic Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {// 请求的地址String requestUrl = ((FilterInvocation) o).getRequestUrl();// 所有的菜单 ,这里可以给一个缓存List<Menu> allMenus = menuService.getAllMenus();for (Menu menu : allMenus) {// 如果请求地址批评上了if (pathMatcher.match(menu.getPattern(), requestUrl)) {List<Role> roles = menu.getRoles();String[] rolesStr = new String[roles.size()];//查看需要哪些角色 rolesStr,防止角色集合for (int i = 0; i < roles.size(); i++) {rolesStr[i] = roles.get(i).getName();}return SecurityConfig.createList(rolesStr);}}// 没有匹配上路径,这个就是标识符号,看在数据库中没有这个路径,怎么处理return SecurityConfig.createList("ROLE_login");}@Overridepublic Collection<ConfigAttribute> getAllConfigAttributes() {return null;}@Overridepublic boolean supports(Class<?> aClass) {return true;}
}

2.7.5 MyAccessDecisionManager


@Component
public class MyAccessDecisionManager implements AccessDecisionManager {/**** @param authentication 当前用户具备的角色* @param o* @param collection  当前路径需要的角色,这里是在MyFiter处理后得到的* @throws AccessDeniedException* @throws InsufficientAuthenticationException*/@Overridepublic void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException {for (ConfigAttribute attribute : collection) {if ("ROLE_login".equals(attribute.getAttribute())) {// 如果是返回的ROLE_login说明你请求的路径不存在,所有判断你有没有登录 登录的就直接放行if (authentication instanceof AnonymousAuthenticationToken) {throw new AccessDeniedException("非法请求!");} else {return;}}// 获取我具备的角色Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();// 做匹配for (GrantedAuthority authority : authorities) {if (authority.getAuthority().equals(attribute.getAttribute())) {return;}}}// 例如,我具备某些角色,但是此角色没有此路径的权限,那就是非要请求throw new AccessDeniedException("非法请求!");}@Overridepublic boolean supports(ConfigAttribute configAttribute) {return true;}@Overridepublic boolean supports(Class<?> aClass) {return true;}
}

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”}]

{"username":"admin", "password":"123","grant_type":"password","client_id":"password","scope":"all","client_secret":"123456",
}

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

换回新的token

{"grant_type":"refresh_token", "refresh_token":"d31082b6-68a7-46b5-937a-62a24b186970","grant_type":"password","client_secret":"123456",
}

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

2.8.1重写UsernamePasswordAuthenticationFilter方法

public class MyAuthenticationFilter extends UsernamePasswordAuthenticationFilter {@Overridepublic Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throwsAuthenticationException {if (!request.getMethod().equals("POST")) {throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());}if (request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)) {//说明用户以 JSON 的形式传递的参数String username = null;String password = null;try {Map<String, String> map = new ObjectMapper().readValue(request.getInputStream(), Map.class);username = map.get("username");password = map.get("password");} catch (IOException e) {e.printStackTrace();}if (username == null) {username = "";}if (password == null) {password = "";}username = username.trim();UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);// Allow subclasses to set the "details" propertysetDetails(request, authRequest);return this.getAuthenticationManager().authenticate(authRequest);}return super.attemptAuthentication(request, response);}

2.8.2注入重写的方法

在securityconfig中写入一下文件

 // 配置支持json登录@BeanMyAuthenticationFilter myAuthenticationFilter() throws Exception {MyAuthenticationFilter filter = new MyAuthenticationFilter();filter.setAuthenticationManager(authenticationManagerBean());return filter;}/**** @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {http.addFilterAt(myAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);}

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

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

  // 配置支持json登录@BeanMyAuthenticationFilter myAuthenticationFilter() throws Exception {MyAuthenticationFilter filter = new MyAuthenticationFilter();filter.setAuthenticationManager(authenticationManagerBean());filter.setAuthenticationSuccessHandler(new AuthenticationSuccessHandler() { //登录成功的处理@Override// authentication保存了登录成功后的信息public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp,Authentication authentication) throws IOException, ServletException {resp.setContentType("application/json;charset=utf-8");PrintWriter out = resp.getWriter();Map<String, Object> map = new HashMap<>();map.put("status", 200);map.put("msg", authentication.getPrincipal());out.write(new ObjectMapper().writeValueAsString(map));out.flush();out.close();}});filter.setAuthenticationFailureHandler(new AuthenticationFailureHandler() {//登录失败的处理@Override // e登录失败的异常public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp,AuthenticationException e) throws IOException, ServletException {resp.setContentType("application/json;charset=utf-8");PrintWriter out = resp.getWriter();Map<String, Object> map = new HashMap<>();map.put("status", 401);if (e instanceof LockedException) {map.put("msg", "账户被锁定,登录失败!");} else if (e instanceof BadCredentialsException) {map.put("msg", "用户名或密码输入错误,登录失败!");} else if (e instanceof DisabledException) {map.put("msg", "账户被禁用,登录失败!");} else if (e instanceof AccountExpiredException) {map.put("msg", "账户过期,登录失败!");} else if (e instanceof CredentialsExpiredException) {map.put("msg", "密码过期,登录失败!");} else {map.put("msg", "登录失败!");}out.write(new ObjectMapper().writeValueAsString(map));out.flush();out.close();}});return filter;}

2.9spring security整合jwt --jwt-demo

2.9.1 JwtLoginFilter 登录的时候给用户token

public class JwtLoginFilter extends AbstractAuthenticationProcessingFilter {// 实现构造方法/**** @param defaultFilterProcessesUrl* @param authenticationManager*/public JwtLoginFilter(String defaultFilterProcessesUrl, AuthenticationManager authenticationManager) {super(new AntPathRequestMatcher(defaultFilterProcessesUrl));setAuthenticationManager(authenticationManager);}/***  提取用户名和密码去做登录** @param req* @param httpServletResponse* @return* @throws AuthenticationException* @throws IOException*/@Overridepublic Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse httpServletResponse)throws AuthenticationException, IOException {// 为了获取登录的数据转换成userUser user = new ObjectMapper().readValue(req.getInputStream(), User.class);return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword()));}// 登录成功的回调 生成jwt@Overrideprotected void successfulAuthentication(HttpServletRequest request, HttpServletResponse resp,FilterChain chain, Authentication authResult) throws IOException, ServletException {Collection<? extends GrantedAuthority> authorities = authResult.getAuthorities();//获取登录用户的角色StringBuffer sb = new StringBuffer();for (GrantedAuthority authority : authorities) {//获取当前角色sb.append(authority.getAuthority()).append(",");}// 生成jwt的tokenString jwt = Jwts.builder().claim("authorities", sb)// 用户的角色.setSubject(authResult.getName()) // 主题.setExpiration(new Date(System.currentTimeMillis() + 60 * 60 * 1000)) // 过期时间.signWith(SignatureAlgorithm.HS512, "findme") // 签名的算法.compact();Map<String, String> map = new HashMap<>();map.put("token", jwt);map.put("msg", "登录成功");resp.setContentType("application/json;charset=utf-8");PrintWriter out = resp.getWriter();out.write(new ObjectMapper().writeValueAsString(map));out.flush();out.close();}// 登录失败/***** @param req* @param resp* @param failed* @throws IOException* @throws ServletException 登录失败的异常,根据异常判断失败的原因*/@Overrideprotected void unsuccessfulAuthentication(HttpServletRequest req, HttpServletResponse resp,AuthenticationException failed) throws IOException, ServletException {Map<String, String> map = new HashMap<>();map.put("msg", "登录失败");resp.setContentType("application/json;charset=utf-8");PrintWriter out = resp.getWriter();out.write(new ObjectMapper().writeValueAsString(map));out.flush();out.close();}

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

public class JwtFilter extends GenericFilterBean {/*** 用户每次登录的时候校验token** @param servletRequest* @param servletResponse* @param filterChain* @throws IOException* @throws ServletException*/@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,FilterChain filterChain) throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest) servletRequest;// token 放在很多地方都可以,此处是默认把token放到请求头中String jwtToken = req.getHeader("authorization");// 解析tokenJws<Claims> jws = Jwts.parser().setSigningKey("findme") // 生成token的签名.parseClaimsJws(jwtToken.replace("Bearer", "")); // 前端的token会自动加一个Bearer,此处需要去掉Claims claims = jws.getBody(); // 登录的信息String username = claims.getSubject();// 用户名 刚才在生成的时候放入了// 拿到登录的角色后要转换成一个list集合解析  此处是当前用户的角色List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList((String) claims.get("authorities"));// new 一个新的tokenUsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, null, authorities);SecurityContextHolder.getContext().setAuthentication(token);// 对过滤器放行filterChain.doFilter(servletRequest,servletResponse);}

2.9.3增加security的相关配置 configure_(HttpSecurity http) _

 // jwt 相关配置http.authorizeRequests().antMatchers(HttpMethod.POST, "/login").permitAll().anyRequest().authenticated().and()// 登录的过滤器.addFilterBefore(new JwtLoginFilter("/login", authenticationManager()), UsernamePasswordAuthenticationFilter.class)// 做校验的过滤器.addFilterBefore(new JwtFilter(), UsernamePasswordAuthenticationFilter.class).csrf().disable();

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

注意在引入依赖的时候引入cloud相关的

2.10.1.AccessTokenConfig

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

2.10.2AuthorizationServer

package com.find.securityswagger.auth;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;import java.util.Arrays;/*** @ClassName JwtAccessTokenConverter* @Description 将用户信息和 JWT 进行转换* @Author find me* @Date 2020/6/25 0025 20:39* @Version 1.0*/
@EnableAuthorizationServer
@Configuration
public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {@AutowiredTokenStore tokenStore;@AutowiredClientDetailsService clientDetailsService;@AutowiredAuthenticationManager authenticationManager;@AutowiredPasswordEncoder passwordEncoder;@AutowiredJwtAccessTokenConverter jwtAccessTokenConverter;//主要用来配置 Token 的一些基本信息,// 例如 Token 是否支持刷新、Token 的存储位置、Token 的有效期以及刷新 Token 的有效期等等。// Token 有效期这个好理解,刷新 Token 的有效期我说一下,// 当 Token 快要过期的时候,我们需要获取一个新的 Token,在获取新的 Token 时候,// 需要有一个凭证信息,这个凭证信息不是旧的 Token,而是另外一个 refresh_token,这个 refresh_token 也是有有效期的。@BeanAuthorizationServerTokenServices tokenServices() {DefaultTokenServices services = new DefaultTokenServices();services.setClientDetailsService(clientDetailsService);services.setSupportRefreshToken(true);services.setTokenStore(tokenStore);services.setAccessTokenValiditySeconds(60 * 60 * 24 * 2);services.setRefreshTokenValiditySeconds(60 * 60 * 24 * 7);TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter));services.setTokenEnhancer(tokenEnhancerChain);return services;}//用来配置令牌端点的安全约束,也就是这个端点谁能访问,谁不能访问。@Overridepublic void configure(AuthorizationServerSecurityConfigurer security) throws Exception {security.allowFormAuthenticationForClients();}//用来配置客户端的详细信息@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.inMemory().withClient("findme").secret(passwordEncoder.encode("123")) //.resourceIds("rid")//资源id.authorizedGrantTypes("password", "refresh_token")//授权类型.scopes("all").redirectUris("http://localhost:6004/index.html");//重定向 uri}//  这里用来配置令牌的访问端点和令牌服务。@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.authenticationManager(authenticationManager).tokenServices(tokenServices());}
}

2.10.3ResourceServerConfig

package com.find.securityswagger.auth;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;/*** @ClassName ResourceServerConfig* @Description* @Author find me* @Date 2020/6/25 0025 20:41* @Version 1.0*/
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {@AutowiredTokenStore tokenStore;//首先在 configure 方法中配置资源 ID 和 TokenStore,这里配置好之后,// 会自动调用 JwtAccessTokenConverter 将 jwt 解析出来,jwt 里边就// 包含了用户的基本信息,所以就不用远程校验 access_token 了。@Overridepublic void configure(ResourceServerSecurityConfigurer resources) throws Exception {//指定资源id stateless配置基于令牌认证
//        resources.resourceId("rid").stateless(true);resources.resourceId("rid").tokenStore(tokenStore);}@AutowiredMyFilter myFilter;@AutowiredMyAccessDecisionManager myAccessDecisionManager;/*** @param http* @throws Exception*/@Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests().withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {@Overridepublic <O extends FilterSecurityInterceptor> O postProcess(O o) {o.setAccessDecisionManager(myAccessDecisionManager);o.setSecurityMetadataSource(myFilter);return o;}}).and().formLogin().permitAll().and().csrf().disable();}
}

2.10.4 GlobalCorsConfiguration —支持跨域

package com.find.securityswagger.swaggerconfig;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;/*** @ClassName GlobalCorsConfiguration* @Description 支持跨域* @Author find me* @Date 2020/6/25 0025 21:36* @Version 1.0*/
@Configuration
public class GlobalCorsConfiguration {@Beanpublic CorsFilter corsFilter() {CorsConfiguration corsConfiguration = new CorsConfiguration();corsConfiguration.setAllowCredentials(true);corsConfiguration.addAllowedOrigin("*");corsConfiguration.addAllowedHeader("*");corsConfiguration.addAllowedMethod("*");UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);return new CorsFilter(urlBasedCorsConfigurationSource);}
}
package com.find.securityswagger.swaggerconfig;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.OAuthBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;import java.util.Arrays;
import java.util.List;/*** @ClassName Swagger2Config* @Description swagger* @Author find me* @Date 2020/6/25 0025 21:19* @Version 1.0*/
@Configuration
@EnableSwagger2
public class Swagger2Config {//    // 手动添加token的方式
//    @Bean
//    Docket docket() {//        return new Docket(DocumentationType.SWAGGER_2)
//                .select()
//                .apis(RequestHandlerSelectors.basePackage("com.find.securityswagger.controller"))
//                .paths(PathSelectors.any())
//                .build()
//                .securityContexts(Arrays.asList(securityContexts()))
//                .securitySchemes(Arrays.asList(securitySchemes()))
//                .apiInfo(new ApiInfoBuilder()
//                        .description("接口文档的描述信息")
//                        .title("微人事项目接口文档")
//                        .contact(new Contact("javaboy","https://www.yuque.com/findme","2354827879@qq.com"))
//                        .version("v1.0")
//                        .license("Apache2.0")
//                        .build());
//    }
//    //通过 securitySchemes 来配置全局参数,这里的配置是一个名为 Authorization 的请求头(OAuth2 中需要携带的请求头)。
//    private SecurityScheme securitySchemes() {//        return new ApiKey("Authorization", "Authorization", "header");
//    }
//
//    // 则用来配置有哪些请求需要携带 Token,这里我们配置了所有请求。
//    private SecurityContext securityContexts() {//        return SecurityContext.builder()
//                .securityReferences(defaultAuth())
//                .forPaths(PathSelectors.any())
//                .build();
//    }
//
//    // 参数
//    private List<SecurityReference> defaultAuth() {//        AuthorizationScope authorizationScope = new AuthorizationScope("xxx", "描述信息");
//        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
//        authorizationScopes[0] = authorizationScope;
//        return Arrays.asList(new SecurityReference("Authorization", authorizationScopes));
//    }// 可以在页面去配置整个登录信息@BeanDocket docket() {return new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.basePackage("com.find.securityswagger.controller")).paths(PathSelectors.any()).build().securityContexts(Arrays.asList(securityContext())).securitySchemes(Arrays.asList(securityScheme())).apiInfo(new ApiInfoBuilder().description("接口文档的描述信息").title("find me demo    ").contact(new Contact("findme","https://www.yuque.com/findme","2354827879@qq.com")).version("v1.0").license("Apache2.0").build());}private AuthorizationScope[] scopes() {return new AuthorizationScope[]{new AuthorizationScope("all", "all scope")};}// 构建时即得配置 token 的获取地址。private SecurityScheme securityScheme() {GrantType grant = new ResourceOwnerPasswordCredentialsGrant("http://127.0.0.1:6004/oauth/token");return new OAuthBuilder().name("OAuth2").grantTypes(Arrays.asList(grant)).scopes(Arrays.asList(scopes())).build();}private SecurityContext securityContext() {return SecurityContext.builder().securityReferences(Arrays.asList(new SecurityReference("OAuth2", scopes()))).forPaths(PathSelectors.any()).build();}
}

swagger的两种配置的效果如下

输入 Bearer ${token}

postman测试参数如下 先获取token,在传递token

2.11configure其他配置

@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests()//开启配置.antMatchers("/admin/**").hasRole("admin")//路径符合这个需要admin角色
//                .antMatchers("user/**").hasAnyRole("admin", "user")//路径符合这个,需要这两个的任意一个.antMatchers("/user/**").access("hasAnyRole('user','admin')").anyRequest().authenticated()//其他请求,登录后就可以访问.and().formLogin()//表单登录.loginProcessingUrl("/doLogin")//处理登录请求的地址.loginPage("/login")//配置登录页面(实际上还是一个请求地址) 前后端分类不存在这种页面 这里还是访问的应该请求,会根据这请求去返回登录页面.usernameParameter("uname")//修改登录的key.passwordParameter("passwd")//修改登录的key.successHandler(new AuthenticationSuccessHandler() { //登录成功的处理@Override// authentication保存了登录成功后的信息public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp,Authentication authentication) throws IOException, ServletException {resp.setContentType("application/json;charset=utf-8");PrintWriter out = resp.getWriter();Map<String, Object> map = new HashMap<>();map.put("status", 200);map.put("msg", authentication.getPrincipal());out.write(new ObjectMapper().writeValueAsString(map));out.flush();out.close();}}).failureHandler(new AuthenticationFailureHandler() {//登录失败的处理@Override // e登录失败的异常public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp,AuthenticationException e) throws IOException, ServletException {resp.setContentType("application/json;charset=utf-8");PrintWriter out = resp.getWriter();Map<String, Object> map = new HashMap<>();map.put("status", 401);if (e instanceof LockedException) {map.put("msg", "账户被锁定,登录失败!");} else if (e instanceof BadCredentialsException) {map.put("msg", "用户名或密码输入错误,登录失败!");} else if (e instanceof DisabledException) {map.put("msg", "账户被禁用,登录失败!");} else if (e instanceof AccountExpiredException) {map.put("msg", "账户过期,登录失败!");} else if (e instanceof CredentialsExpiredException) {map.put("msg", "密码过期,登录失败!");} else {map.put("msg", "登录失败!");}out.write(new ObjectMapper().writeValueAsString(map));out.flush();out.close();}}).permitAll().and().logout().logoutUrl("/logout") //配置注销请求的地址.logoutSuccessHandler(new LogoutSuccessHandler() {//注销成功后的回调@Overridepublic void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp,Authentication authentication) throws IOException, ServletException {resp.setContentType("application/json;charset=utf-8");PrintWriter out = resp.getWriter();Map<String, Object> map = new HashMap<>();map.put("status", 200);map.put("msg", "注销登录成功!");out.write(new ObjectMapper().writeValueAsString(map));out.flush();out.close();}}).and().csrf().disable();/*** 权限不足处理*/http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {@Overridepublic void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException {httpServletResponse.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);Map<String, Object> failureMap = new HashMap<>();failureMap.put("code", 403);failureMap.put("msg", "权限不足!");httpServletResponse.getWriter().println(objectMapper.writeValueAsString(failureMap));}});
//        /**
//         * 未登陆处理
//         */
//        http.exceptionHandling().authenticationEntryPoint(new AuthenticationEntryPoint() {//            @Override
//            public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException {//
//
//                httpServletResponse.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
//
//                Map<String, Object> failureMap = new HashMap<>();
//                failureMap.put("code", 401);
//                failureMap.put("msg", "请先登录!");
//
//                httpServletResponse.getWriter().println(objectMapper.writeValueAsString(failureMap));
//
//            }
//        });
//

1.spring security简单的demo-适合萌新相关推荐

  1. SpringBoot + Spring Security 简单入门

    这篇文章主要介绍了SpringBoot + Spring Security 简单入门 Spring Security 基本介绍 这里就不对Spring Security进行过多的介绍了,具体的可以参考 ...

  2. spring security简单配置

    spring security简单配置 主要集中在5个类里面配置 1,实现UserDetailsService 2,实现AuthenticationManager 3,登录成功与失败的处理 4,访问拒 ...

  3. idea中新建maven项目缺少src目录的根本解决方法(适合萌新 少走弯路)

    idea中新建maven项目缺少src目录的根本解决方法(适合萌新 少走弯路) 参考了很多博客,基本都是让在setting下的runner 添加-DarchetypeCatalog=internal参 ...

  4. Spring Security——简单第三方OAuth2登录自动配置——GitHub登录DEMO

    GitHub OAuth2 APP申请 https://github.com/settings/applications/new Maven <!--Spring Security-->& ...

  5. spring security简单教程以及实现完全前后端分离

    spring security是spring家族的一个安全框架,入门简单.对比shiro,它自带登录页面,自动完成登录操作.权限过滤时支持http方法过滤. 在新手入门使用时,只需要简单的配置,即可实 ...

  6. Spring Security简单SSO

    问题 简单使用Spring Security实现简单单点登录. 思路 引入Spring Security ,Spring Session Redis相关库,简单配置Spring Security实现对 ...

  7. Spring Security简单增加短信验证码登录

    查网上资料增加短信验证码登录都要增加一大推,要重头写Spring Security的实现,我呢,只想在原来的密码登录基础上简单实现一下短信验证码登录. 1.首先得先一个认证类,来认证验证码是否正确,这 ...

  8. Spring Security简单理解

    最近在学习Spring Security,于是就写了这篇Spring Security的博客来记录自己的学习中的一些总结,本文主要是一些简单的原理分析,没有涉及很深的源码分析. 1. Spring S ...

  9. spring security 简单理解

    一.简介 Spring Security 是 Spring 家族中的一个安全管理框架. 一般来说,常见的安全管理技术栈的组合是这样的: SSM + Shiro Spring Boot/Spring C ...

最新文章

  1. 如何启用SQL Server 2008的FILESTREAM特性
  2. 网站服务器高主频还是多核心,CPU核心多好还是主频高好?核心多和主频高区别介绍...
  3. 关于System.Web.Caching的“未将对象引用设置到对象的实例”错误
  4. 跟踪DB2的sql语句
  5. AtCoder AGC037D Sorting a Grid (二分图匹配)
  6. matlab guidata两个,Matlab
  7. 3-8 译码器设计实验--VHDL
  8. Doule类型转成十六进制查看
  9. Oracle性能调优
  10. 得到jar包运行时所在的目录
  11. 程序媛学车之——科目二流程
  12. 根据先序序列和中序,后序和中序序列创建二叉树
  13. dcs与plc与c语言的联系,PLC 与DCS的通讯方式,举例讲解
  14. 苹果Mac系统虚拟打印机CAD输出PDF文档软件—pdfwriter
  15. 东大22春《计算机应用基础》在线平时作业3_100分参考非答案
  16. 定义一个抽象类一水果,创建若干水果对象存放在-一个水果类型的数组中,输出数组中所有水果的类型、重量
  17. 01_国家卫生部PACS相关标准
  18. 分布式事务(Seata) 四大模式详解
  19. 记录一下,simulink使用导入的机械臂CAD模型
  20. H264视频GOP组和视频压缩技术之有损压缩(帧间压缩、帧内压缩)、无损压缩(ACBAC压缩)

热门文章

  1. 2021-05-16刷题
  2. 戴特科技工业4.0丨通用技术取代工厂车间专用工具
  3. matlab基于遗传算法的BP神经网络优化算法(附代码)
  4. 推挽电路---采用二极管消除交越失真----克服交越失真的互补推挽输出电路图
  5. 校招失败后,在小公司熬了 2 年终于进了华为,竭尽全力....
  6. 58同城笔试:后端开发编程题
  7. DELL台式机Linux ubuntu 20.04.5 安装
  8. 用OneNote打造全平台的数字笔记本
  9. 爱奇艺迎史上最大裁员潮:总监说撸就撸,有的部门直接裁一半......
  10. Springboot项目集成Minio文件服务器(下)