赞
踩
目录
security干啥的?
认证和授权
使用方式
引入依赖, 基于spring boot的下的使用.
spring-boot-starter-security, 直接可以使用了.
观察一下
姿源分类
受保护的资源, 需要认证
公共方式, 不需要认证.
当我们把security引入到项目当中的时候,我们去访问一下受保护的资源,会弹出一个默认的一个登录界面.用户名称默认的是: user, 密码随机生成的.通过uuid生成的.如果认证成功,则直接跳转到要访问的接口.
基本原理
SecurityAutoConfiguration, spring security自动配置类.默认配置.如果我们啥也不干,则直接走默认配置.界面了,用户名称和密码都是默认生成的.
如果想要覆盖掉默认配置,则我们用两种方案.
继承一个类WebSecurityConfigurerAdapter, 重写方法.
将SecurityFilterChain放到容器当中.
- /**
- * {@link Condition} for
- * {@link ConditionalOnDefaultWebSecurity @ConditionalOnDefaultWebSecurity}.
- *
- * @author Phillip Webb
- */
- class DefaultWebSecurityCondition extends AllNestedConditions {
-
- DefaultWebSecurityCondition() {
- super(ConfigurationPhase.REGISTER_BEAN);
- }
-
- @ConditionalOnClass({ SecurityFilterChain.class, HttpSecurity.class })
- static class Classes {
-
- }
-
- // 当IoC容器当中没有WebSecurityConfigurerAdapter.class, SecurityFilterChain.class 这两个类的对象
- // 则默认生效,否则默认配置不生效.
- @ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class })
- static class Beans {
-
- }
-
- }

默认的配置类
SecurityProperties
- @ConfigurationProperties(prefix = "spring.security")
- public class SecurityProperties {}
对认证资源进行配置
可以针对某一些资源,不进行认证, 默认是都进行认证的.
此时我们就覆盖掉默认配置.
- public HttpSecurity authorizeRequests(
- Customizer<ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer)
- throws Exception {
- ApplicationContext context = getContext();
- authorizeRequestsCustomizer
- .customize(getOrApply(new ExpressionUrlAuthorizationConfigurer<>(context)).getRegistry());
- return HttpSecurity.this;
- }
认证成功之后的处理:
- public final T successHandler(AuthenticationSuccessHandler successHandler) {
- this.successHandler = successHandler;
- return getSelf();
- }
- package com.tingyi.configs;
-
- import com.fasterxml.jackson.databind.ObjectMapper;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.security.config.annotation.web.builders.HttpSecurity;
- import org.springframework.security.core.Authentication;
- import org.springframework.security.web.SecurityFilterChain;
- import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
-
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import java.io.IOException;
- import java.io.PrintWriter;
- import java.util.HashMap;
- import java.util.Map;
-
- /**
- * @author 听忆
- */
- @Configuration
- public class SecurityConfig {
-
- @Bean
- public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
- return http.authorizeRequests(authorize ->
- authorize.mvcMatchers("/tom")
- .permitAll()
- .anyRequest()
- .authenticated())
- .formLogin()
- // .successForwardUrl("/success") // 默认的话,跳转到你在认证之前的请求.
- // .defaultSuccessUrl("/success", true) // true,表示强制跳转到指定的url
- .successHandler(new AuthenticationSuccessHandler() { // security提供给我们的,认证成功之后的处理.我们可以在这里返回json给前端.
-
-
-
- // 前后端分离项目使用的方式;
- @Override
- public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
- // 给前端返回一个json串.应用于前后端分离的项目.
- Map<String, Object> map = new HashMap<>();
- map.put("code", 0); // 状态码
- map.put("msg", "认证成功");
- map.put("authentication", authentication);
-
- PrintWriter writer = response.getWriter();
- String json = new ObjectMapper().writeValueAsString(map);
- writer.print(json);
- }
- }).and()
- .csrf(csrf -> csrf.disable())
- .build();
- }
- }

认证流程:
浏览器输入了用户名称和密码 —> 服务器 –> security 进行认证, 怎么认证的?
UsernamePasswordAuthenticaionFilter
AbstractAuthenticationProcessingFilter
我们去认证的时候,服务器把密码存储到哪里地了.
UserDetailsService
UserDetailsManager, 用户信息管理.接口.封装了对用户所有操作.
InMemoryUserDetailsManager, 基于内存实现的.也就是说,将用户信息都存储在内存当中了.
DaoAuthenticationProvider
- protected void additionalAuthenticationChecks(UserDetails userDetails,
- UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
- if (authentication.getCredentials() == null) {
- this.logger.debug("Failed to authenticate since no credentials provided");
- throw new BadCredentialsException(this.messages
- .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
- }
- String presentedPassword = authentication.getCredentials().toString();
- if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
- this.logger.debug("Failed to authenticate since password does not match stored value");
- throw new BadCredentialsException(this.messages
- .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
- }
- }
数据放到了内存当中,使用的是: InMemoryUserDetailsManager, 从内存读取数据,实际开发当中,数据源, 一般情况来自于数据库.也就是说, 我们存储用户名称和密码应该是存储在数据当中,咱们进行认证的时候,应该是从数据当中获取用户名称和密码.替换掉默认的: InMemoryUserDetailsManager.
通过查看,类关系图.发现有一个接口: UserDetailsService
- package org.springframework.security.core.userdetails;
- // 如果我们要自定义实现读取的数据源, 则必须实现这个接口,重写这个方法.
- public interface UserDetailsService {
- // 通过用户名称获取用户的详细信息.
- // 返回值是一个UserDetails接口.实际上返回的应该是一个对象.
- UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
- }
- package org.springframework.security.core.userdetails;
-
- import java.io.Serializable;
- import java.util.Collection;
-
- import org.springframework.security.core.Authentication;
- import org.springframework.security.core.GrantedAuthority;
-
- /**
- * Provides core user information.
- *
- * <p>
- * Implementations are not used directly by Spring Security for security purposes. They
- * simply store user information which is later encapsulated into {@link Authentication}
- * objects. This allows non-security related user information (such as email addresses,
- * telephone numbers etc) to be stored in a convenient location.
- * <p>
- * Concrete implementations must take particular care to ensure the non-null contract
- * detailed for each method is enforced. See
- * {@link org.springframework.security.core.userdetails.User} for a reference
- * implementation (which you might like to extend or use in your code).
- *
- * @author Ben Alex
- * @see UserDetailsService
- * @see UserCache
- * 用户详细信息
- * 1. 用户名称
- * 2. 用户密码
- * 3. 用户的权限列表
- * 1. 角色信息
- * 2. 权限信息
- */
- public interface UserDetails extends Serializable {
-
- /**
- * Returns the authorities granted to the user. Cannot return <code>null</code>.
- * @return the authorities, sorted by natural key (never <code>null</code>)
- * 权限列表
- */
- Collection<? extends GrantedAuthority> getAuthorities();
-
- /**
- * Returns the password used to authenticate the user.
- * @return the password
- * 获取用户密码
- */
- String getPassword();
-
- /**
- * Returns the username used to authenticate the user. Cannot return
- * <code>null</code>.
- * @return the username (never <code>null</code>)
- * 用户名称
- */
- String getUsername();
-
- /**
- * Indicates whether the user's account has expired. An expired account cannot be
- * authenticated.
- * @return <code>true</code> if the user's account is valid (ie non-expired),
- * <code>false</code> if no longer valid (ie expired)
- * 账号状态是否是过期的.
- */
- boolean isAccountNonExpired();
-
- /**
- * Indicates whether the user is locked or unlocked. A locked user cannot be
- * authenticated.
- * @return <code>true</code> if the user is not locked, <code>false</code> otherwise
- */
- boolean isAccountNonLocked();
-
- /**
- * Indicates whether the user's credentials (password) has expired. Expired
- * credentials prevent authentication.
- * @return <code>true</code> if the user's credentials are valid (ie non-expired),
- * <code>false</code> if no longer valid (ie expired)
- */
- boolean isCredentialsNonExpired();
-
- /**
- * Indicates whether the user is enabled or disabled. A disabled user cannot be
- * authenticated.
- * @return <code>true</code> if the user is enabled, <code>false</code> otherwise
- */
- boolean isEnabled();
-
- }

User, spring security提供的一个类,这个类实现了UserDetails接口.
- // username,表示我们根据用户名称,从内存或者数据库查询出来的用户名称.
- // password, 从内存或者数据库当中查询出来的密码
- // authorities, 从内存或者数据库当中查询出来该用户名称对应的权限列表.
- public User(String username, String password, Collection<? extends GrantedAuthority> authorities) {
- this(username, password, true, true, true, true, authorities);
- }
重要的接口和实现类:
UserDetailsService,
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; // 根据前端传递过来的用户名称,去数据当中查询出用户名称对应的详细信息,封装成UserDetails对象即可;
InMemoryUserDetailsManager,它是一个实现类,它表示从内存当中读取.
我们如果要换成从数据库当中读取用户信息,则必须实现UserDetailsService接口,重写方法.查询出来的数据,封里成UserDetatils对象.
UserDetails, 表示定义用户的各种各样的信息.
用户名称
用户密码
用户权限列表
实现类: User, 在UserDetailsService方法, loadUserByUsername返回它即可;
如果, controller当中的login,直接调用Service层,此时需要我们自己处理,整个验证过程.
现在我们如果在userDetailsService实现类当中,进行相关的业务处理,将验证过程直接交给了security. 不用我们操心了.
根据流程来说, 要将从内存获取数据方式改更从数据库进行查询.
自己定义一个UserDetailsService实现类,完成一个逻辑:
①. 根据用户名称去数据库查询出这个用户名称对应的数据.
②. 将查询出来的数据封装成UserDetails对象.
- package com.tingyi.service.impl;
-
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.qf.entity.TbUser;
- import com.qf.mapper.ITbUserMapper;
- import org.springframework.security.core.GrantedAuthority;
- import org.springframework.security.core.userdetails.User;
- import org.springframework.security.core.userdetails.UserDetails;
- import org.springframework.security.core.userdetails.UserDetailsService;
- import org.springframework.security.core.userdetails.UsernameNotFoundException;
- import org.springframework.stereotype.Service;
-
- import java.util.Collections;
- import java.util.List;
-
- /**
- * @author 听忆
- * 自定义读取过程,之前是从在内存当中,根据用户名称获取用户详情,现在我们从数据库当中进行获取.
- * mybatis plus 来读取一下.
- */
- @Service
- public class UserDetailsServiceImpl implements UserDetailsService {
- private final ITbUserMapper tbUserMapper;
-
- public UserDetailsServiceImpl(ITbUserMapper tbUserMapper) {
- this.tbUserMapper = tbUserMapper;
- }
-
- @Override
- public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
- // 根据用户名称去数据库当中查找.
- LambdaQueryWrapper<TbUser> queryWrapper = new LambdaQueryWrapper<>();
- queryWrapper.eq(TbUser::getUsername, username);
- // 查询出结果,根据咱们自己就没有处理它.
- TbUser user = tbUserMapper.selectOne(queryWrapper); // 通过这个对象,获取密码.还有权限列表.
- // 最终我们得把获取到的数据封装成UserDetails对象.交给spring security处理去.
- List<GrantedAuthority> grantedAuthorityList = Collections.emptyList(); // 权限列表.
- // 封装UserDetails对象.
- // User是UserDetails实现类.所以咱们可以直接返回这个实现类对象.
- return new User(username, user.getPassword(), grantedAuthorityList);
- }
- }
-

手动完成认证
整个spring security一共15个过滤器. 其中有一个负责账号密码认证的过滤器: UsernamePasswordAuthenticationFilter
.
需要一个认证管理器:
AutenticationManager, 咱们是配置类,将它注入到IoC容器当中.
- @Bean
- public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
- return authenticationConfiguration.getAuthenticationManager();
- }
直接调用认证方法:
- @Override
- public Result login(String username, String password) {
- try {
- // 1. 将用户名称和密码封装成UsernamePasswordAuthenticationToken.
- UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
- new UsernamePasswordAuthenticationToken(username, password);
-
- // 2. 调用AuthenticationManager提供认证方法.
- // Authentication authenticate(Authentication authentication) throws AuthenticationException;
- Authentication authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
-
- // 3. 存储认证结果.
- SecurityContextHolder.getContext().setAuthentication(authenticate);
- return Result.success("认证成功", authenticate);
- }catch (AuthenticationException e){
- return Result.error("认证失败", e.getMessage());
- }
- }

更改配置文件
得去执行我们自己的认证页面.
- @Bean
- public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
- return http.authorizeRequests(authorize ->
- authorize.mvcMatchers("/tom", "/login")
- .permitAll()
- .anyRequest()
- .authenticated())
- // .formLogin() // 仅仅表示我使用表单验证, 但是配置用的都是默认的.
- .formLogin(form -> form.loginPage("/login.html").permitAll()
- .successHandler(new AuthenticationSuccessHandler() {
- @Override
- public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
- // 给前端返回一个json串.应用于前后端分离的项目.
- response.setContentType("application/json;charset=utf-8");
- Map<String, Object> map = new HashMap<>();
- map.put("code", 0); // 状态码
- map.put("msg", "认证成功");
- map.put("authentication", authentication);
-
- PrintWriter writer = response.getWriter();
- String json = new ObjectMapper().writeValueAsString(map);
- writer.print(json);
- }
- }).failureHandler(new AuthenticationFailureHandler() {
- @Override
- public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
- // 给前端返回一个json串.应用于前后端分离的项目.
- response.setContentType("application/json;charset=utf-8");
- Map<String, Object> map = new HashMap<>();
- map.put("code", -1); // 状态码
- map.put("msg", "认证失败");
- map.put("exception", exception);
-
- PrintWriter writer = response.getWriter();
- String json = new ObjectMapper().writeValueAsString(map);
- writer.print(json);
- }
- }))
-
- // .successForwardUrl("/success") // 默认的话,跳转到你在认证之前的请求.
- // .defaultSuccessUrl("/success", true) // true,表示强制跳转到指定的url
- .csrf(csrf -> csrf.disable())
- .build();
- }

- <dependency>
- <groupId>io.jsonwebtoken</groupId>
- <artifactId>jjwt-api</artifactId>
- <version>0.11.2</version>
- </dependency>
- <dependency>
- <groupId>io.jsonwebtoken</groupId>
- <artifactId>jjwt-impl</artifactId>
- <version>0.11.2</version>
- <scope>runtime</scope>
- </dependency>
- <dependency>
- <groupId>io.jsonwebtoken</groupId>
- <artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
- <version>0.11.2</version>
- <scope>runtime</scope>
- </dependency>
-
- <!--解决高版本JDK问题-->
- <!--javax.xml.bind.DatatypeConverter错误-->
- <dependency>
- <groupId>javax.xml.bind</groupId>
- <artifactId>jaxb-api</artifactId>
- <version>2.3.0</version>
- </dependency>
- <dependency>
- <groupId>com.sun.xml.bind</groupId>
- <artifactId>jaxb-impl</artifactId>
- <version>2.3.0</version>
- </dependency>
- <dependency>
- <groupId>com.sun.xml.bind</groupId>
- <artifactId>jaxb-core</artifactId>
- <version>2.3.0</version>
- </dependency>
- <dependency>
- <groupId>javax.activation</groupId>
- <artifactId>activation</artifactId>
- <version>1.1.1</version>
- </dependency>

JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。
安全, 以json方式传输, 可以被验证和信任.本质还是一个字符串.定义规则,咱们可控的.
- package com.tingyi.utils;
-
- import io.jsonwebtoken.Claims;
- import io.jsonwebtoken.JwtBuilder;
- import io.jsonwebtoken.Jwts;
- import io.jsonwebtoken.SignatureAlgorithm;
-
- import javax.crypto.spec.SecretKeySpec;
- import javax.xml.bind.DatatypeConverter;
- import java.security.Key;
- import java.util.Date;
- import java.util.UUID;
-
- /**
- * jwt工具类.
- */
- public class JwtUtil {
- /**
- * jwt过期时间
- */
- public static final Long EXP_TTL = 60 * 60 * 1000L;
-
- /**
- * jwt使用的密钥
- */
- public static final String JWT_KEY = "c3R1ZHkgaGFyZCBhbmQgbWFrZSBwcm9ncmVzcyBldmVyeSBkYXku";
-
- /**
- * 创建jwt字符串
- * @param id id
- * @param issuer 创建的作者
- * @param subject 用户主体
- * @param ttlMillis 过期时间, 毫秒值
- * @return jwt字符串
- */
- public static String createJWT(String id, String issuer, String subject, long ttlMillis) {
- SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
- long nowMillis = System.currentTimeMillis();
- Date now = new Date(nowMillis);
-
- byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(JWT_KEY);
- Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
-
- JwtBuilder builder = Jwts
- .builder()
- .setId(id)
- .setIssuedAt(now)
- .setSubject(subject)
- .setIssuer(issuer)
- .signWith(signingKey, signatureAlgorithm);
-
- if (ttlMillis >= 0) {
- long expMillis = nowMillis + ttlMillis;
- Date exp = new Date(expMillis);
- builder.setExpiration(exp);
- }
- return builder.compact();
- }
-
- /**
- * 创建jwt字符串
- * @param issuer 作者信息
- * @param subject 用户主体信息
- * @param ttlMillis 过期时间, 毫秒值
- * @return jwt字符串
- */
- public static String createJwt(String issuer, String subject, long ttlMillis){
- return createJWT(uuid(), issuer, subject, ttlMillis);
- }
-
- /**
- * 创建jwt字符串
- * @param issuer 作者信息
- * @param subject 用户主体信息
- * @return jwt字符串
- */
- public static String createJwt(String issuer, String subject){
- return createJwt(issuer, subject, EXP_TTL);
- }
-
- /**
- * 创建jwt字符串
- * @param subject 用户主体
- * @return jwt字符串
- */
- public static String createJwt(String subject){
- return createJwt("laoren", subject, EXP_TTL);
- }
-
- /**
- * uuid
- * @return String
- */
- private static String uuid(){
- return UUID.randomUUID().toString().replaceAll("-", "");
- }
-
- /**
- * 解析jwt
- * @param jwt jwt字符串
- * @return Claims
- */
- public static Claims parseJWT(String jwt) {
- Claims claims = Jwts.parserBuilder()
- .setSigningKey(DatatypeConverter.parseBase64Binary(JWT_KEY))
- .build()
- .parseClaimsJws(jwt).getBody();
-
- return claims;
- }
-
- public static void main(String[] args) {
- // 生成一个jwt串.
- String jwt = createJWT("1024", "tom", "jack", EXP_TTL);
- System.out.println(jwt);
- // 解析jwt串.
- Claims claims = parseJWT(jwt);
- Object subject = claims.get("subject");
- System.out.println(subject);
- System.out.println(claims);
- System.out.println(claims.getSubject());
- System.out.println(claims.getIssuedAt());
- System.out.println(claims.getExpiration());
- }
- }

RBAC(Role-Based Access Control)
,基于角色的访问控制。通过用户关联角色,角色关联权限,来间接的为用户赋予权限。
下面是标准的RBAC模型关系表:
用户表
- -- 用户表
- CREATE TABLE `sys_user` (
- `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
- `name` varchar(50) NOT NULL COMMENT '用户名',
- `nick_name` varchar(150) DEFAULT NULL COMMENT '昵称',
- `password` varchar(100) DEFAULT NULL COMMENT '密码',
- `create_time` datetime DEFAULT NULL COMMENT '创建时间',
- PRIMARY KEY (`id`),
- UNIQUE KEY `name` (`name`)
- ) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8 COMMENT='用户管理';
角色表
- -- 角色表
- CREATE TABLE `sys_role` (
- `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
- `name` varchar(100) DEFAULT NULL COMMENT '角色名称',
- `create_time` datetime DEFAULT NULL COMMENT '创建时间',
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 COMMENT='角色管理';
用户角色表
- -- 用户角色表
- CREATE TABLE `sys_user_role` (
- `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
- `user_id` bigint(20) DEFAULT NULL COMMENT '用户ID',
- `role_id` bigint(20) DEFAULT NULL COMMENT '角色ID',
- `create_time` datetime DEFAULT NULL COMMENT '创建时间',
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=88 DEFAULT CHARSET=utf8 COMMENT='用户角色';
菜单表
- -- 菜单表
- CREATE TABLE `sys_menu` (
- `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
- `name` varchar(50) DEFAULT NULL COMMENT '菜单名称',
- `parent_id` bigint(20) DEFAULT NULL COMMENT '父菜单ID,一级菜单为0',
- `url` varchar(200) DEFAULT NULL COMMENT '菜单URL,类型:1.普通页面(如用户管理, /sys/user) 2.嵌套完整外部页面,以http(s)开头的链接 3.嵌套服务器页面,使用iframe:前缀+目标URL(如SQL监控, iframe:/druid/login.html, iframe:前缀会替换成服务器地址)',
- `perms` varchar(500) DEFAULT NULL COMMENT '授权(多个用逗号分隔,如:sys:user:add,sys:user:edit)',
- `type` int(11) DEFAULT NULL COMMENT '类型 0:目录 1:菜单 2:按钮',
- `icon` varchar(50) DEFAULT NULL COMMENT '菜单图标',
- `order_num` int(11) DEFAULT NULL COMMENT '排序',
- `create_time` datetime DEFAULT NULL COMMENT '创建时间',
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=57 DEFAULT CHARSET=utf8 COMMENT='菜单管理';
角色菜单表
- -- 角色菜单表
- CREATE TABLE `sys_role_menu` (
- `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
- `role_id` bigint(20) DEFAULT NULL COMMENT '角色ID',
- `menu_id` bigint(20) DEFAULT NULL COMMENT '菜单ID',
- `create_time` datetime DEFAULT NULL COMMENT '创建时间',
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=623 DEFAULT CHARSET=utf8 COMMENT='角色菜单';
按照: 认证的过程,其中实现了接口: UserDetailsService接口,之后,我们在重写的方法当中.
- @Override
- public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
- LambdaQueryWrapper<TbUser> queryWrapper = new LambdaQueryWrapper<>();
- queryWrapper.eq(TbUser::getUsername, username);
- TbUser user = tbUserMapper.selectOne(queryWrapper); // 通过这个对象,获取密码.还有权限列表.
- // 最终我们得把获取到的数据封装成UserDetails对象.交给spring security处理去.
- // 这个集合当中,包含两个东西
- // 角色列表, 应该通过用户id去数据库当中,通过多表查询给它查询出来. List<Role>
- // 权限列表, 通过用户id, 去数据库当中,通过多表查询,权限查出来. List<Menu>
- List<GrantedAuthority> grantedAuthorityList = Collections.emptyList(); // 权限列表.
-
- // 上一步完成之后,将封装好的List<GrantedAuthority>交给spring security,它会在我们需要验证权限的时候,就会给你验证了.
- // 如何知道我需要进行权限验证,当类上或者方法上标记相关注解了.则表示我需要验证了.
- // 当前登录的用户,是否有某个角色.
- // 当前登录的用户, 是否拥有这个权限.
- return new User(username, user.getPassword(), grantedAuthorityList);
- }

@Secured注解, 是否拥有某个角色,某些角色.
@PreAuthorize, 是否拥有某些权限.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。