当前位置: 首页 > news >正文

北京怎么做网站推广wordpress顶部加横幅

北京怎么做网站推广,wordpress顶部加横幅,网页特效大全,邢台做网站优化前言#xff1a;本系列博客基于Spring Boot 2.6.x依赖的Spring Security5.6.x版本 上一篇博客介绍了Spring Security的整体架构#xff0c;本篇博客要讲的是Spring Security的认证和鉴权两个重要的机制。 UsernamePasswordAuthenticationFilter和BasicAuthenticationFilter是… 前言本系列博客基于Spring Boot 2.6.x依赖的Spring Security5.6.x版本 上一篇博客介绍了Spring Security的整体架构本篇博客要讲的是Spring Security的认证和鉴权两个重要的机制。 UsernamePasswordAuthenticationFilter和BasicAuthenticationFilter是用来认证的两个过滤器FilterSecurityInterceptor是用来鉴权的。 一、Spring Security认证 Spring Security提供了许多认证机制例如用户名密码认证、OAuth 2.0认证、SAML认证、Central Authentication Server (CAS)认证、Remember Me记住过了session有效期的用户、JAAS认证、X509认证等 1.1、认证架构 Spring Security认证架构主要由以下几个组件构成 SecurityContextSpring Security的上下文对象包含了当前认证用户的Authentication认证。 SecurityContextHolder用于设置和获取SecurityContext的静态工具类保存了SecurityContext上下文对象。 Authentication认证接口定义了获取用户凭证、认证信息、权限等方法规范。 GrantedAuthority权限类用来定义用户的权限Authentication中会保存一个GrantedAuthority类型的权限列表。 AuthenticationManager认证管理器接口只有一个authenticate方法它的实现类实现该方法用来执行具体的认证逻辑入参和出参都是Authentication。 ProviderManager最常见的AuthenticationManager的实现。 AuthenticationProvider认证功能提供者接口。在ProviderManager中实际上的认证逻辑由该接口的实现类处理。DaoAuthenticationProvider、AnonymousAuthenticationProvider都是它的实现类。 AuthenticationEntryPoint用于从客户端请求凭证即重定向到登录页面返回需要登录响应等。 AbstractAuthenticationProcessingFilter一个用于认证的基本 Filter。是一个抽象类只有UsernamePasswordAuthenticationFilter一个实现UsernamePasswordAuthenticationFilter会从请求中获取username和 password参数去进行认证。 1.1.1、SecurityContext Spring Security的上下文对象可以设置和获取Authentication认证信息。 public interface SecurityContext extends Serializable {// 获取Authentication对象Authentication getAuthentication();// 放入Authentication对象void setAuthentication(Authentication authentication); }1.1.2、SecurityContextHolder SecurityContextHolder是用来设置和获取SecurityContext的静态工具类SecurityContextHolder不关心SecurityContext里认证信息的细节即Authentication的具体实现类型是什么它并不关心如果它能获取到值这个值就认为是当前用户的认证信息。 public class SecurityContextHolder {...//常用方法public static void clearContext() {strategy.clearContext();}public static SecurityContext getContext() {return strategy.getContext();}public static void setContext(SecurityContext context) {strategy.setContext(context);}... }SecurityContextHolder架构图 默认情况下SecurityContextHolder使用ThreadLocal来存储这些细节这意味着 SecurityContext 对同一线程中的方法总是可用的即使SecurityContext没有被明确地作为参数传递给这些方法。并且Spring Security的FilterChainProxy会确保SecurityContext总是被清空不用我们手动清空。 1.1.3、Authentication Authentication是认证信息接口定义了获取用户凭证、认证信息、权限等方法规范。它主要有两个作用一是充当未认证的用户凭证包括用户名、密码一是表示验证后的认证信息包括认证后用户信息、用户权限等。Authentication一般包含了如下信息 principal: 识别用户。当用用户名/密码进行认证时这通常是 UserDetails 的一个实例。 credentials: 通常是一个密码。在许多情况下这在用户被认证后被清除以确保它不会被泄露。 authorities: GrantedAuthority 实例是用户被授予的权限。 public interface Authentication extends Principal, Serializable {//获取用户权限一般情况下获取到的是用户的角色信息Collection? extends GrantedAuthority getAuthorities();//获取证明用户认证的信息通常情况下获取到的是密码等信息Object getCredentials();//获取用户的额外信息这部分信息可以是我们的用户表中的信息Object getDetails();// 获取用户身份信息在未认证的情况下获取到的是用户名在已认证的情况下获取到的是 UserDetailsObject getPrincipal();//获取当前 Authentication 是否已认证boolean isAuthenticated();//设置当前 Authentication 是否已认证true or falsevoid setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException; }1.1.4、GrantedAuthority Spring Security定义的权限类规范接口认证后的用户权限就是以GrantedAuthority类型的集合保存的。使用时分两种权限分别是角色role和作用域scope。role类型的权限表示该权限为角色角色可能会对应许多的具体资源菜单、接口等权限scope表示某个具体资源的权限。一般使用role类型的权限因为使用scope的话认证时可能会保存有非常多的GrantedAuthority容易导致内存不足而role类型基本没有这种问题。注意设置role类型的权限时权限最好加上ROLE_ 前缀Spring Security默认的role类型鉴权方法会有ROLE_ 前缀。 public interface GrantedAuthority extends Serializable {//拿到权限名String getAuthority(); }1.1.5、AuthenticationManager 认证管理器接口定义了执行认证逻辑的方法API。常用的实现类为ProviderManager。 public interface AuthenticationManager {//用户执行认证时的方法具体逻辑由实现类实现Authentication authenticate(Authentication authentication) throws AuthenticationException; }1.1.6 、ProviderManager ProviderManager是最常用的AuthenticationManager的实现。ProviderManager委托给一个 AuthenticationProvider集合。每个 AuthenticationProvider都有机会表明认证应该是成功的、失败的或者表明它不能做出决定并允许下游的AuthenticationProvider来决定。如果配置的 AuthenticationProvider实例中没有一个能进行认证那么认证就会以ProviderNotFoundException 而失败这是一个特殊的AuthenticationException表明ProviderManager没有被配置为支持被传入它的Authentication类型。 1.1.7、AuthenticationProvider 实际上执行认证逻辑的地方。常用的实习类DaoAuthenticationProvider支持基于用户名/密码的认证、AnonymousAuthenticationProvider匿名用户认证 public interface AuthenticationProvider {//执行具体认证逻辑Authentication authenticate(Authentication authentication) throws AuthenticationException;boolean supports(Class? authentication); }1.1.8、AuthenticationEntryPoint 如果用户访问一个需要认证后才能访问的资源AuthenticationEntryPoint就会返回一个响应需要用户先认证后或者携带认证凭证再访问。比如重定向到登录页面或者返回一个携带“需要登录”提示的响应信息。我们可以实现该接口自定义的未登录认证提示。Spring Security默认会对未认证去访问需要认证的资源的请求返回403。 1.1.9、AbstractAuthenticationProcessingFilter 用户认证的基础Filter只有UsernamePasswordAuthenticationFilter这一个实现类。 AbstractAuthenticationProcessingFilter源码 public abstract class AbstractAuthenticationProcessingFilter extends GenericFilterBean implements ApplicationEventPublisherAware, MessageSourceAware {...//主要方法public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {this.doFilter((HttpServletRequest)request, (HttpServletResponse)response, chain);}private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {//先校验请求url与表单校验提交的url是否一致不一致执行下一个Filter//一致的话就执行认证逻辑一般默认的表单提交url是/loginif (!this.requiresAuthentication(request, response)) {chain.doFilter(request, response);} else {try {//实现类执行具体的认证逻辑Authentication authenticationResult this.attemptAuthentication(request, response);if (authenticationResult null) {return;}this.sessionStrategy.onAuthentication(authenticationResult, request, response);if (this.continueChainBeforeSuccessfulAuthentication) {chain.doFilter(request, response);}this.successfulAuthentication(request, response, chain, authenticationResult);} catch (InternalAuthenticationServiceException var5) {this.logger.error(An internal error occurred while trying to authenticate the user., var5);this.unsuccessfulAuthentication(request, response, var5);} catch (AuthenticationException var6) {this.unsuccessfulAuthentication(request, response, var6);}}}//由子类实现具体的验证逻辑public abstract Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException;... }UsernamePasswordAuthenticationFilter的 attemptAuthentication() 方法 public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {if (this.postOnly !request.getMethod().equals(POST)) {throw new AuthenticationServiceException(Authentication method not supported: request.getMethod());} else {//取用户名实际上是从request取username参数String username this.obtainUsername(request);username username ! null ? username : ;username username.trim();//取密码实际上是从request取password参数String password this.obtainPassword(request);password password ! null ? password : ;UsernamePasswordAuthenticationToken authRequest new UsernamePasswordAuthenticationToken(username, password);this.setDetails(request, authRequest);return this.getAuthenticationManager().authenticate(authRequest);}}AbstractAuthenticationProcessingFilter认证步骤 1、当用户提交他们的凭证用户名和密码时AbstractAuthenticationProcessingFilter会从HttpServletRequest中创建一个要认证的Authentication。创建的认证的类型取决于 AbstractAuthenticationProcessingFilter的子类。例如UsernamePasswordAuthenticationFilter从HttpServletRequest中提交的username和password创建一个 UsernamePasswordAuthenticationToken。 2、接下来Authentication被传入AuthenticationManager执行认证逻辑。 3、如果认证失败则为Failure。 SecurityContextHolder被清空。 RememberMeServices.loginFail被调用。如果没有配置记住我remember me可以忽略。 AuthenticationFailureHandler被调用。参考AuthenticationFailureHandler接口。 4、 如果认证成功则为Success。 SessionAuthenticationStrategy被通知有新的登录。参考SessionAuthenticationStrategy接口。 Authentication是在SecurityContextHolder上设置的。如果你需要保存SecurityContext以便在未来的请求中自动设置必须显式调用SecurityContextRepository#saveContext。参考 SecurityContextHolderFilter类。 RememberMeServices.loginSuccess 被调用。如果没有配置remember me可以忽略。 ApplicationEventPublisher发布一个InteractiveAuthenticationSuccessEvent事件。 AuthenticationSuccessHandler被调用。参考AuthenticationSuccessHandler接口。 1.2、代码示例 1.2.1、默认登录认证 引入需要用到的相关包。 dependencies!-- 如果你项目的maven父工程是spring-boot-starter-parent包可以不写版本号springboot管理了版本号--!--Spring Security--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-security/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactIdexclusionsexclusiongroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-tomcat/artifactId/exclusion/exclusions/dependency!--使用undertow容器--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-undertow/artifactId/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-thymeleaf/artifactId/dependencydependencygroupIdorg.apache.commons/groupIdartifactIdcommons-lang3/artifactId/dependency/dependencies定义一个controller Controller public class LoginController {//主页urlRequestMapping(/main)public String mainPage(){return main;} }在resource/templates/ 路径下里定义一个main.html作为主页 !DOCTYPE html html langen xmlns:thhttp://www.thymeleaf.org headmeta charsetUTF-8title主页面/title /head bodyh1主页面/h1form th:action{/logout} methodpostinput typesubmit value登出/form /body /htmlapplication.yml server:port: 8084servlet:context-path: /securityspring:security:#配置Spring Security默认登录用户和密码#不配置的话启动项目时Spring Security会在控制台打印出默认密码用户名是Useruser:name: Userpassword: 123456一切准备就绪启动项目访问localhost:8084/security/main,会自动重定向到Spring Security的默认登录页面。 这是因为Spring Security使用了默认的表单登录认证的方式。查看控制台打印信息可以看到类似下面的输出。 如果没有可能是Spring Security的版本问题我使用的Spring Boot-2.6.2引入的Spring Security-5.6.2关于这一块的打印信息逻辑写错了导致未打印可以将Spring Boot版本升级一下。 2023-06-14T08:55:22.321-03:00 INFO 76975 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Will secure any request with [ org.springframework.security.web.session.DisableEncodeUrlFilter404db674, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter50f097b5, org.springframework.security.web.context.SecurityContextHolderFilter6fc6deb7, org.springframework.security.web.header.HeaderWriterFilter6f76c2cc, org.springframework.security.web.csrf.CsrfFilterc29fe36, org.springframework.security.web.authentication.logout.LogoutFilteref60710, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter7c2dfa2, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter4397a639, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter7add838c, org.springframework.security.web.authentication.www.BasicAuthenticationFilter5cc9d3d0, org.springframework.security.web.savedrequest.RequestCacheAwareFilter7da39774, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter32b0876c, org.springframework.security.web.authentication.AnonymousAuthenticationFilter3662bdff, org.springframework.security.web.access.ExceptionTranslationFilter77681ce4, org.springframework.security.web.access.intercept.AuthorizationFilter169268a7]UsernamePasswordAuthenticationFilter过滤器就是用来表单登录认证的Filter。 1.2.2、自定义登录页面 在resource/templates/ 路径下里定义一个login.html作为登录页 !DOCTYPE html html langen xmlns:thhttp://www.thymeleaf.org headmeta charsetUTF-8title登录页面/title /head bodyh1登录页面/h1!--method必须为post--!--th:action{/login},使用动态参数表单中会自动生成_csrf隐藏字段用于防止csrf攻击login和登录页面保持一致即可SpringSecurity自动进行登录认证/login 是Spring Security默认的登录认证路径默认情况下用户名和密码名称必须是username和password--form th:action{/login} methodpost用户名input typetext nameusername br密码input typepassword namepasswordbrinput typesubmit/form /body /htmlLoginController添加登录页面跳转接口 RequestMapping(/myLoginPage)public String myLoginPage(){return login;}自定义Spring Security的配置类 Configuration public class BasicSecurityConfig {Beanpublic SecurityFilterChain mySecurityFilterChain(HttpSecurity http) throws Exception {// 登录相关配置http.formLogin(formLogin - formLogin.loginPage(/myLoginPage) // 自定义登录页面不再使用内置的自动生成页面//登录认证接口url这里可以任意设置只要保证和登录表单提交的url相同即可.loginProcessingUrl(/login).usernameParameter(username)// 表单中的用户名项.passwordParameter(password)// 表单中的密码项.successForwardUrl(/main)//登录成功后跳转的路径未设置会跳转到项目根路径);//设置访问权限如果不设置默认所有的url都可以匿名访问http.authorizeRequests(authorize -{authorize.antMatchers(/myLoginPage).permitAll() //允许所有用户访问.anyRequest() //对所有请求开启授权保护.authenticated(); //已认证的请求会被自动授权});http.logout(logout -logout.logoutUrl(/logout) //使用该方法时当开启csrf防护logout请求必须是post否则会404.clearAuthentication(true) //清除认证状态默认为true.invalidateHttpSession(true) // 销毁HttpSession对象默认为true);//关闭csrf防护,否则所有的POST的请求都需要携带CSRF令牌http.csrf(csrf - csrf.disable());return http.build(); // 返回构建的SecurityFilterChain实例} }还有一种写法是继承WebSecurityConfigurerAdapter类重写configure方法但是Spring Security 6.0及之后的版本删除了WebSecurityConfigurerAdapter类不能用这种写法配置了。 Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter {Overridepublic void configure(HttpSecurity http) throws Exception {//和上面配置相同最后无需调用http.build()方法....} }注意使用表单登录认证时实际处理认证的是UsernamePasswordAuthenticationFilter类loginProcessingUrl方法配置的url可以任意配置只要和登录表单提交的url相同即可。 1.2.3、自定义Handler逻辑 Spring Security定义了一些Handler接口让我们可以自定义认证结束后的处理逻辑。比如返回JSON结果适用于前后端分离的项目。 1.2.3.1、认证成功处理 AuthenticationSuccessHandler类是Spring Security提供的认证成功后处理逻辑接口。 实现AuthenticationSuccessHandler接口 public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {// 获取用户身份信息UserDetails userDetails (UserDetails)authentication.getPrincipal();// 获取用户的凭证信息Object credentials authentication.getCredentials();// 获取用户权限信息Collection? extends GrantedAuthority authorities authentication.getAuthorities();/*返回页面适用于前后端未分离的项目*/System.out.println(用户名:userDetails.getUsername());System.out.println(一些操作...);//response.sendRedirect(request.getContextPath()/main);/*返回json适用于前后端分离*///这里可以生成token并存redis等MapString,Object result new HashMap();result.put(code,0); // 成功result.put(message,登录成功); //result.put(data,userDetails); //这里可以换成tokenjwt等登录成功凭证// 将结果对象转换成json字符串String json JSON.toJSONString(result);// 返回json数据到前端// 响应头response.setContentType(application/json;charsetUTF-8);// 响应体response.getWriter().println(json);} } 在BasicSecurityConfig配置类的formLogin中加上MyAuthenticationSuccessHandler // 登录相关配置http.formLogin(formLogin - formLogin.loginPage(/myLoginPage) // 自定义登录页面不再使用内置的自动生成页面//登录认证接口url这里可以任意设置只要保证和登录表单提交的url相同即可.loginProcessingUrl(/login).usernameParameter(username)// 表单中的用户名项.passwordParameter(password)// 表单中的密码项.successForwardUrl(/main)//登录成功后跳转的路径未设置会跳转到项目根路径.successHandler(new MyAuthenticationSuccessHandler()) //认证成功处理);1.2.3.2、认证失败处理 AuthenticationFailureHandler类是Spring Security提供的认证失败处理逻辑接口。 实现AuthenticationFailureHandler接口 public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {// 获取失败的信息String localizedMessage exception.getLocalizedMessage();MapString,Object result new HashMap();result.put(code,-1); // 失败result.put(message,localizedMessage); //// 将结果对象转换成json字符串String json JSON.toJSONString(result);// 返回json数据到前端// 响应头response.setContentType(application/json;charsetUTF-8);// 响应体response.getWriter().println(json);//重定向到登录错误页面适用与前后端不分离项目//response.sendRedirect(request.getContextPath()/loginError);} }在BasicSecurityConfig配置类的formLogin中加上MyAuthenticationFailureHandler // 登录相关配置http.formLogin(formLogin - formLogin....successHandler(new MyAuthenticationSuccessHandler()) //认证成功处理.failureHandler(new MyAuthenticationFailureHandler()) //认证失败处理);1.2.3.3、登出成功处理 LogoutSuccessHandler类是Spring Security提供的登出成功处理逻辑接口。 实现LogoutSuccessHandler接口 public class MyLogoutSuccessHandler implements LogoutSuccessHandler {Overridepublic void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {// 获取用户身份信息UserDetails userDetails (UserDetails)authentication.getPrincipal();/** 返回json适用于前后端分离*/MapString,Object result new HashMap();result.put(code,1); // 成功result.put(message,注销成功); //result.put(data,userDetails); //// 将结果对象转换成json字符串String json JSON.toJSONString(result);// 返回json数据到前端 适用前后端分离// 响应头response.setContentType(application/json;charsetUTF-8);// 响应体response.getWriter().println(json);//返回到页面//response.sendRedirect(request.getContextPath()/main);} }在BasicSecurityConfig配置类的logout中加上MyLogoutSuccessHandler http.logout(logout -logout.logoutUrl(/logout) //使用该方法时当开启csrf防护logout请求必须是post否则会404.clearAuthentication(true) //清除认证状态默认为true.invalidateHttpSession(true) // 销毁HttpSession对象默认为true.logoutSuccessHandler(new MyLogoutSuccessHandler()));1.2.3.4、请求未认证资源处理 AuthenticationEntryPoint类是Spring Security提供的未认证访问资源处理逻辑接口。 实现AuthenticationEntryPoint类 public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {String localizedMessage 需要登录;//authException.getLocalizedMessage();MapString,Object result new HashMap();result.put(code,-1); // 告诉用户需要登录result.put(message,localizedMessage); //// 将结果对象转换成json字符串String json JSON.toJSONString(result);// 返回json数据到前端// 响应头response.setContentType(application/json;charsetUTF-8);// 响应体response.getWriter().println(json);//返回登录界面//response.sendRedirect(request.getContextPath()/myLoginPage);} }在BasicSecurityConfig配置类的中加上配置 //异常处理http.exceptionHandling(exception - exception.authenticationEntryPoint(new MyAuthenticationEntryPoint()) //请求未认证的处理);1.2.4、基于数据库的认证 前面的示例中我们的登录用户是写在配置文件里的用的是基于内存存储用户信息的方式。这只能在学习时使用在实际项目中是不行的。实际项目中我们的用户信息时存在数据库里的Spring Security也提供了基于数据库来进行认证的方式。 前文我们已经说过通过HttpSecurity的formLogin方法配置的认证是使用UsernamePasswordAuthenticationFilter类来进行的认证处理而实际上处理时是在ProviderManager的authenticate方法里再调用DaoAuthenticationProvider的authenticate方法处理的。最终的处理是在DaoAuthenticationProvider类的父类AbstractUserDetailsAuthenticationProvider类的authenticate处理的。 而在进行认证前需要先根据用户名查询系统里的用户数据内存或数据库再根据查询到的用户密码与用户输入的密码校验校验通过则认证成功。这一块的逻辑是由DaoAuthenticationProvider类重写父类的retrieveUser实现的。源码如下 protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {this.prepareTimingAttackProtection();try {//拿到用户信息UserDetails loadedUser this.getUserDetailsService().loadUserByUsername(username);if (loadedUser null) {throw new InternalAuthenticationServiceException(UserDetailsService returned null, which is an interface contract violation);} else {return loadedUser;}} catch (UsernameNotFoundException var4) {this.mitigateAgainstTimingAttack(authentication);throw var4;} catch (InternalAuthenticationServiceException var5) {throw var5;} catch (Exception var6) {throw new InternalAuthenticationServiceException(var6.getMessage(), var6);}}通过调用UserDetailsService的loadUserByUsername方法返回系统的用户信息。我们可以通过实现自己的UserDetailsService实现类重写loadUserByUsername方法查询数据库里的用户数据。代码如下 public class DBUserDetailsManager implements UserDetailsManager, UserDetailsPasswordService {/*** UserDetails提供的字段如果不够的话可以继承 User类实现自己的UserDetails* 用户认证时会调用* param username* return* throws UsernameNotFoundException*/Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//根据userName去数据库查询用户信息, 伪代码UserDomain user userService.queryUserByUserName(username);if(user null){throw new UsernameNotFoundException(username);}//查询用户的角色伪代码ListString roles roleService.getRoleCodeByUserId(user.getId());UserDetails userDetails User.withUsername(user.getLoginName()).password(user.getPassword())//.authorities(roles.toArray(new String[roles.size()])) //权限和roles配一个就行这里配置不会加前缀.roles(roles.toArray(new String[roles.size()])) //角色 配置角色时会给资源自动加上ROLE_前缀.build();return userDetails;}Overridepublic void createUser(UserDetails user) {}Overridepublic void updateUser(UserDetails user) {}Overridepublic void deleteUser(String username) {}Overridepublic void changePassword(String oldPassword, String newPassword) {}Overridepublic boolean userExists(String username) {return false;}Overridepublic UserDetails updatePassword(UserDetails user, String newPassword) {return null;} }然后在配置类中加上相关配置 Configuration public class BasicSecurityConfig {.../*** 密码编码器,会对请求传入的密码进行加密* return*/Beanpublic PasswordEncoder passwordEncoder() {//return NoOpPasswordEncoder.getInstance();return new BCryptPasswordEncoder();}Beanpublic UserDetailsService userDetailsService(){return new DBUserDetailsManager();}... } 需要加一个密码编码器使用Spring Security提供的默认编码器就行使用编码器后注意数据库保存的密码应该是密文。直接将我们的UserDetailsService注入到Spring容器中即可生效。 二、Spring Security鉴权 2.1、鉴权架构 2.1.1、FilterSecurityInterceptor Spring Security进行鉴权处理的入口。父类是AbstractSecurityInterceptor类 2.1.2、AccessDecisionManager Spring Security鉴权的真正处理者 public interface AccessDecisionManager {//鉴权方法 /*** authentication 当前用户的认证凭证信息包括了用户信息权限等* object 一般是FilterInvocation包含了当前请求的request和response* configAttributes过滤规则由配置类里的 HttpSecurity的authorizeRequests方法配置*/void decide(Authentication authentication, Object object, CollectionConfigAttribute configAttributes) throws AccessDeniedException, InsufficientAuthenticationException;//是否允许AccessDecisionManager处理该过滤规则true为允许boolean supports(ConfigAttribute attribute);//是否允许AccessDecisionManager处理clazz类型true为允许boolean supports(Class? clazz); }Spring Security的鉴权是基于投票机制的鉴权方式。 2.1.3、AccessDecisionVoter 投票器AccessDecisionManager的投票处理是由AccessDecisionVoter投票器决定的一个AccessDecisionManager里会包含一个AccessDecisionVoter集合AccessDecisionManager会根据所有投票器的投票结果来决定请求是否有权访问无权限会抛出一个 AccessDeniedException。 public interface AccessDecisionVoterS {//同意int ACCESS_GRANTED 1;//弃权int ACCESS_ABSTAIN 0;//反对int ACCESS_DENIED -1;boolean supports(ConfigAttribute attribute);boolean supports(Class? clazz);//投票方法int vote(Authentication authentication, S object, CollectionConfigAttribute attributes); } AccessDecisionManager有三个实现类 AffirmativeBased一票通过只要有一票通过就算通过默认是它。UnanimousBased一票反对只要有一票反对就不能通过。ConsensusBased少数票服从多数票。 2.2、代码示例 2.2.1、默认鉴权 定义两个接口分别由两种权限访问。在LoginController中新增 //admin权限RequestMapping(/adminRole)ResponseBodypublic String adminRole(){return success;}//tourist权限RequestMapping(/touristRole)ResponseBodypublic String touristRole(){return success;}在BasicSecurityConfig配置类中新增这两个接口鉴权配置 Beanpublic SecurityFilterChain mySecurityFilterChain(HttpSecurity http) throws Exception {//和前文一样的配置省略了...//设置访问权限如果不设置默认所有的url都可以匿名访问http.authorizeRequests(authorize -{authorize// 放行所有OPTIONS请求.antMatchers(HttpMethod.OPTIONS).permitAll().antMatchers(/myLoginPage).permitAll() //登录页面允许所有用户访问.antMatchers(/adminRole).hasRole(AdminManager) // /adminRole 只能AdminManager角色访问.antMatchers(/touristRole).hasAnyRole(AdminManager,ApproveUser) // /touristRole AdminManager和ApproveUser角色都能访问.anyRequest() //对所有请求开启授权保护.authenticated(); //已认证的请求会被自动授权});...return http.build(); // 返回构建的SecurityFilterChain实例}通过给“/adminRole”和/touristRole接口配置权限过滤规则用户访问接口时就会在登录认证成功后在SecurityContext上下文中设置凭证信息其中就包括当前用户的权限然后匹配配置的权限过滤规则判断当前用户是否有该接口的权限。如果不配置权限过滤规则则默认认证成功的用户都可以访问。 前文说过在进行表单登录认证时Spring Security是通过调用UserDetailsService的loadUserByUsername方法得到当前登录用户的信息的其中就包括权限信息。 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//根据userName去数据库查询用户信息, 伪代码UserDomain user userService.queryUserByUserName(username);if(user null){throw new UsernameNotFoundException(username);}//查询用户的角色伪代码ListString roles roleService.getRoleCodeByUserId(user.getId());UserDetails userDetails User.withUsername(user.getLoginName()).password(user.getPassword())//.authorities(roles.toArray(new String[roles.size()])) //权限和roles配一个就行这里配置不会加前缀.roles(roles.toArray(new String[roles.size()])) //角色 配置角色时会给资源自动加上ROLE_前缀.build();return userDetails;}通过Spring Security的User类的roles和authorities方法就可以设置当前登录用户的权限信息。这里需要注意的是如果配置权限过滤规则时使用的是role角色权限loadUserByUsername方法也得设置role权限反之亦然。权限名称相同即可。 2.2.2、请求未授权接口处理 Spring Security定义了AccessDeniedHandler接口用来处理访问未授权接口的请求。只需实现AccessDeniedHandler接口然后将自定义的类加入到配置里即可。 public class MyAccessDeniedHandler implements AccessDeniedHandler {Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {MapString,Object result new HashMap();result.put(code,-1); // 没有权限result.put(message,没有权限); //// 将结果对象转换成json字符串String json JSON.toJSONString(result);// 返回json数据到前端// 响应头response.setContentType(application/json;charsetUTF-8);// 响应体response.getWriter().println(json);//返回页面//response.sendRedirect(request.getContextPath()/main);} }在BasicSecurityConfig配置类中加上该类 Beanpublic SecurityFilterChain mySecurityFilterChain(HttpSecurity http) throws Exception {...//异常处理http.exceptionHandling(exception - exception.authenticationEntryPoint(new MyAuthenticationEntryPoint()) //请求未认证的处理.accessDeniedHandler(new MyAccessDeniedHandler()) //未授权处理);//关闭csrf防护,否则所有的POST的请求都需要携带CSRF令牌http.csrf(csrf - csrf.disable());return http.build(); // 返回构建的SecurityFilterChain实例}2.2.3、基于方法注解的方式鉴权 Spring Security提供了基于注解的方式设置权限过滤规则的方法。具体使用如下 使用EnableMethodSecurity注解开启基于方法的授权在自定义的BasicSecurityConfig配置类上加上即可 Configuration EnableMethodSecurity public class BasicSecurityConfig {... }然后在Controller的方法上使用PreAuthorize注解即可。首先在配置类里去掉/adminRole和/touristRole的权限过滤规则配置。然后在LoginController里给这两个接口加上PreAuthorize注解 RequestMapping(/adminRole)ResponseBodyPreAuthorize(hasAnyRole(AdminManager))public String adminRole(){return success;}RequestMapping(/touristRole)ResponseBodyPreAuthorize(hasAnyRole(AdminManager,ApproveUser))public String touristRole(){return success;}PreAuthorize里可以使用SpEL表达式例如hasRole(‘ADMIN’) and authentication.name ‘User’ 这种。可以使用的规则如下 具体可以参考Spring Security关于这一块的官网介绍 https://springdoc.cn/spring-security/servlet/authorization/authorize-http-requests.html#authorization-expressions 相类似的注解还有PostAuthorize、PreFilter、PostFilter等。具体的用法也可以去官网查找。
http://www.hkea.cn/news/14347225/

相关文章:

  • 网站建设模板型和定制型网站底部信息
  • 湛江网站制作优化凡客诚品还有人买吗
  • 做网站官网好处怎么在中国做网站网站
  • 网站建设需求分析调研表电子商务以后的就业方向
  • 网站开发周期是什么意思西安哪个公司做网站
  • 推网站wordpress 自适应主题
  • 电子商务网站营销方案永州企业网站开发
  • 购物网站建设过程做算法题网站
  • 帝国cms地方门户网站模板做网站策划需要什么技能
  • 安康做网站的公司电话北京网站seo招聘
  • 网站 流程 工具wordpress文件简易版
  • 江宁做网站j建设局域网网站
  • 关于网站建设论文的结束语做货代的要注册哪种物流网站
  • 网站制作赚钱吗常德百竞seo
  • 辽宁省建设工程信息网官网新网站入口官方环保工程 技术支持 东莞网站建设
  • 主题网站设计与制作长春网站推广公司
  • 个人电脑做网站环保网站 下载
  • 西宁平台网站建设一般网站的前台功能模块
  • 网站规划要点曲靖企业网站
  • 怎么做网站计划网站开发维护入哪个科目
  • 宠物网站建设的可行性寻找企业网站建设
  • 优惠卷网站建设怎么挣钱黄冈app下载推广平台
  • 网站建设备案查询wordpress动态效果
  • 怎么查看网站主机商深圳软件开发公司推荐
  • dede网站底部门户网站规划
  • 浙江平台网站建设找哪家i深圳app是哪个公司开发的
  • 济南网站建设 行知科技找深圳网站建设
  • 免费查企业电话网站h5生成
  • 淄博学校网站建设公司网站建设讯美
  • 海南企业网站做优化排名知名网站制作公