应用jwt token来认证和鉴权
<!--jwt配置文件-->
<dependency>

<groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.0</version>

</dependency>

(jwt也可,只须要将userDto的信息应用jwt来保留即可返回时,返回jwt的字符串,我这是将用户信息保留在了redis中)

1、配置security文件

/**

  • SpringSecurity的配置
  • Created by wenye on 2021/4/12.
    */

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowiredprivate RestfulAccessDeniedHandler restfulAccessDeniedHandler;@Autowiredprivate RestAuthenticationEntryPoint restAuthenticationEntryPoint;// 下面是登录认证相干  上面为url权限相干 - ========================================================================================/** * 获取拜访url所须要的角色信息 */@Autowiredprivate  UrlFilterInvocationSecurityMetadataSource urlFilterInvocationSecurityMetadataSource;/** * 认证权限解决 - 将下面所取得角色权限与以后登录用户的角色做比照,如果蕴含其中一个角色即可失常拜访 */@Autowiredprivate  UrlAccessDecisionManager urlAccessDecisionManager;/** * 自定义拜访无权限接口时403响应内容 */@Autowiredprivate  UrlAccessDeniedHandler urlAccessDeniedHandler;@Autowiredprivate MyuserDetailsService userDetailsService;//申请权限配置@Overrideprotected void configure(HttpSecurity http) throws Exception {    http.csrf().disable()            .sessionManagement()            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)            .and()            .authorizeRequests()            .antMatchers("/login/user/employee/login", "/login/user/employee/register")// 对登录注册要容许匿名拜访            .permitAll()            .antMatchers(HttpMethod.OPTIONS)//跨域申请会先进行一次options申请            .permitAll()            .authenticated();    ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http.authorizeRequests();    registry.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {                                         @Override                                         public <O extends FilterSecurityInterceptor> O postProcess(O o) {                                             o.setSecurityMetadataSource(urlFilterInvocationSecurityMetadataSource);                                             o.setAccessDecisionManager(urlAccessDecisionManager);                                             return o;                                         }                                     });    // 增加JWT filter    http.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);    //增加自定义未受权和未登录后果返回    http.exceptionHandling()            .accessDeniedHandler(restfulAccessDeniedHandler)            .authenticationEntryPoint(restAuthenticationEntryPoint);}@Beanpublic JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {    return new JwtAuthenticationTokenFilter();}

/* 能够不要哦

@Overridepublic void configure(WebSecurity web) throws Exception {    // 设置拦挡疏忽文件夹,能够对动态资源放行    web.ignoring().antMatchers("/css/**", "/js/**");}*/

}

2、usercontroller
@RestController
@RequestMapping("/login/user")
@Api(tags = "用户体系")
public class SysUserController {

@Autowiredprivate ITbSysEmployeeService tbSysEmployeeService;@Autowiredprivate RedisToolCache redisToolCache;@Autowiredprivate RedisTemplate redisTemplate;/** * 员工登录 * @param dto * @return */@RequestMapping("/employee/login")public RespMessage employeelogin(@RequestBody LoginDto dto){    //数据校验@Valid    RespMessage respMessage = tbSysEmployeeService.employeelogin(dto, TokenChannelEnum.WEB.getValue());    try {        beanLife();    } catch (Exception e) {        e.printStackTrace();    }    if (ObjectUtils.isEmpty(respMessage)){        return RespHandler.failure("账户名明码谬误");    }    return respMessage;}

}

3、UserDot 存储直达用户信息
@Data
public class UserDto implements Serializable {

private String phone;private String userId;private String passwd;private String validCode;private String module;//登陆的模块private String userName;//登录用户名private Long rentId;//租户ID(指定租户ID登录)private String appType;//利用类型:1Android,2IOS,private String newPasswd;private Integer channel;private String token;private List<String> roles;private String avatar;

}

4、userserviceImpl
@Service
public class TbSysEmployeeServiceImpl extends ServiceImpl<TbSysEmployeeDao, TbSysEmployeeEntity> implements ITbSysEmployeeService {

@Autowiredprivate TbSysEmployeeDao tbSysEmployeeDao;@Autowiredprivate TokenManager tokenManager;@Overridepublic RespMessage  employeelogin(LoginDto dto, int channel) {    if (ObjectUtils.isEmpty(dto)) {        return null;    }    TbSysEmployeeEntity employee1 = tbSysEmployeeDao.employeeOne(dto.getUserName());    if (ObjectUtils.isEmpty(employee1)) {        return null;    }    //校验明码    String pwd = "";    try {        pwd = EncryptionUtil.SHA1(EncryptionUtil.SHA1(dto.getPassword()+employee1.getSalt()));    } catch (Exception e) {        e.printStackTrace();    }    if (! pwd.equals( employee1.getPassword())) {        return null;    }//生成token、存储日志    UserDto userDto = new UserDto();    userDto.setUserId(employee1.getId());    userDto.setModule(String.valueOf(channel));    userDto.setUserName(employee1.getNickName());    userDto.setPhone(employee1.getPhone());    List<Integer> list = CommonUtils.intToIntegerList(employee1.getRole());    List<String> roles = new ArrayList<>();    for (Integer i : list) {        if (i == 1) {            roles.add("admin");        }else {            roles.add("");        }    }    userDto.setRoles(roles);    userDto.setAvatar(employee1.getAvatar());    //生成token    String token = tokenManager.createToken(userDto);    TbSysLoginLogEntity entity = new TbSysLoginLogEntity();    entity.setUserName(employee1.getName());    entity.setPhone(employee1.getPhone());    entity.setOperateType(1);    entity.setDeviceType(1);    tbSysLoginLogService.save(entity);    userDto.setToken(token);    return RespHandler.success(userDto);}

}

5、tokenmanger
就是reids的创立,获取,校验,返回1个32位的UUID字符串就行

6、ITbSysEmployeeService 员工信息查问
public class TbSysEmployeeImpl extends ServiceImpl<TbSysEmployeeDao, TbSysEmployeeEntity> implements ITbSysEmployeeService {

@Autowiredprivate TbSysEmployeeDao tbSysEmployeeDao;@Overridepublic TbSysEmployeeEntity selectByUsername(String username) {    TbSysEmployeeEntity entity = null;    try {        entity = tbSysEmployeeDao.employeeOne(username);    } catch (Exception e) {        e.printStackTrace();    }    return entity;}

}

对应的sql 只有获取用户名称,明码,权限列表就ok了,这里nick_name为用户名,
SELECT
se.id,
se.name,
se.phone,
se.card,
se.password,
se.status,
se.nick_name,
se.code,
se.address,
se.create_name,
se.create_time,
se.update_time,
se.salt,
se.avatar,
sr.ROLETYPE_ID role
FROM tb_sys_employee se
left join tb_sys_user_role sur on sur.USER_ID = se.id
left join tb_sys_role sr on sr.id = sur.role_id
WHERE 1 = 1
<if test="userName != null and userName != ''">

and se.nick_name = #{userName}

</if>

7、JwtAuthenticationTokenFilter token过滤器
我这只是通过token去redis中查问用户信息,如果用jwt可间接解析字符串中用户信息
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

@Autowiredprivate MyuserDetailsService userDetailsService;@Autowiredprivate TokenManager tokenManager;@Autowiredprivate JwtTokenUtil jwtTokenUtil;

// @Value("${jwt.tokenHeader}")

private String tokenHeader = "Authorization";

// @Value("${jwt.tokenHead}")

private String tokenHead = "Bearer";@Overrideprotected void doFilterInternal(HttpServletRequest request,                                HttpServletResponse response,                                FilterChain chain) throws ServletException, IOException {    //获取token    String authHeader = request.getHeader(this.tokenHeader);    //解析token    if (authHeader != null && tokenManager.checkToken(authHeader)) {        //解析token获取用户名称        UserDto userDto = (UserDto) tokenManager.getToken(authHeader);        String userName = userDto.getUserName();        Authentication authentication1 = SecurityContextHolder.getContext().getAuthentication();        if (userName != null && SecurityContextHolder.getContext().getAuthentication() == null) {            //返回security用户受权对象            UserDetails userDetails = this.userDetailsService.loadUserByUsername(userName);            //判断token是否生效            if (tokenManager.checkToken(authHeader)) {                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());                //资源 的起源存储                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));                //Authentication 对象退出到上下文中期待ProviderManager 去去解决验收信息                SecurityContextHolder.getContext().setAuthentication(authentication);            }        }    }    //转发给过滤器链高低一个对象。这里的下一个指的是下一个filter,    chain.doFilter(request, response);}

}

8、通过用户名称获取用户信息和权限
/**

  • @author :wenye
  • @date :Created in 2021/4/7 11:49
  • @description:校验身份
  • @version: 1.0.0$
    */

@Component
public class MyuserDetailsService implements UserDetailsService {

private Logger logger = LoggerFactory.getLogger(MyuserDetailsService.class);@Autowiredprivate ITbSysEmployeeService tbSysEmployeeService;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {    TbSysEmployeeEntity entity = tbSysEmployeeService.selectByUsername(username);    //校验明码    if (ObjectUtils.isEmpty(entity)) {        throw new BadCredentialsException("请输出正确用户名");    }    //生成token、存储日志    UserDto userDto = new UserDto();    userDto.setUserId(entity.getId());    userDto.setUserName(entity.getNickName());    userDto.setPhone(entity.getPhone());    userDto.setPasswd(entity.getPassword());    //留神这里要革新,骚操作须要更改,此处获取数据库中的用户权限,    //我数据库中存的是组成的二进制组合相加如合乎 1 2 4 8各自代表一个权限 如:7 就是由 1 2 4 组成而后对应判断权限    不过太难顶了(保护起来)。    Lis\t<Integer> list = CommonUtils.intToIntegerList(entity.getRole());    List<String> roles = new ArrayList<>();    for (Integer i : list) {        if (i == 1) {            roles.add("admin");        }else {            roles.add("");        }    }    userDto.setRoles(roles);    userDto.setAvatar(entity.getAvatar());    //据用户名查找用户信息,用户名和明码    //AuthorityUtils.commaSeparatedStringToAuthorityList("admin") 把字符串转化为对应的对象,以逗号分隔字符串    List<String> roles1 = userDto.getRoles();    //解析    StringBuilder rolestr = new StringBuilder();    roles1.stream().forEach(e->{        rolestr.append(e+",");    });    logger.info("用户名为:{}",username);    return new User(username,userDto.getPasswd(), AuthorityUtils.commaSeparatedStringToAuthorityList(rolestr.toString()));}

}

9、用户名,明码校验
@Component
public class MyPasswordEncoder implements PasswordEncoder {

private Logger logg = LoggerFactory.getLogger(MyPasswordEncoder.class);@Autowiredprivate ITbSysEmployeeService tbSysEmployeeService;/** *  编码原始明码。通常,良好的编码算法利用SHA-1或更大的哈希与8字节或更大的随机生成的盐相结合。 * @param rawPassword 明码,一个可读的字符值序列 * @return */@Overridepublic String encode(CharSequence rawPassword) {    logg.info("原始明码:{}", rawPassword);    return rawPassword.toString();}/** * 验证从存储中取得的编码明码是否与提交的原始明码匹配。如果明码匹配,返回true;如果不匹配,返回false。存储的明码自身永远不会被解码。 * @param username 预设的验证明码。要编码和匹配的原始明码 * @param encodedPassword 表单输出的明码。来自存储的编码明码与之比拟 * @return */@Overridepublic boolean matches(CharSequence username, String encodedPassword) {    logg.info("预设的验证明码:{}", username);    logg.info("表单输出的明码:{}", encodedPassword);    TbSysEmployeeEntity entity = tbSysEmployeeService.selectByUsername((String) username);    //校验明码    String pwd = "";    try {        pwd = EncryptionUtil.SHA1(EncryptionUtil.SHA1(encodedPassword+entity.getSalt()));    } catch (Exception e) {        e.printStackTrace();    }    if (! pwd.equals( entity.getPassword())) {        throw new BadCredentialsException("请输出正确的明码");    }    return true;}

}

10、动静url权限管制(重点呜呜,坑了我半天)
@Component
public class UrlFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

@AutowiredTbSysPermissionDao permissionMapper;/*** * 返回该url所须要的用户权限信息 * * @param object: 贮存申请url信息 * @return: null:标识不须要任何权限都能够拜访 */@Overridepublic Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {    // 获取以后申请url    String requestUrl = ((FilterInvocation) object).getRequestUrl();    // TODO 疏忽url请放在此处进行过滤放行,呜呜坑我半天    List<String> urlList = new ArrayList<>();    urlList.add("/login/user/employee/login");    urlList.add("/login/user/employee/register");    if (urlList.contains(requestUrl)) {        return null;    }    // 数据库中所有url    List<TbSysPermissionEntity> permissionList = permissionMapper.selectList(null);    for (TbSysPermissionEntity permission : permissionList) {        // 获取该url所对应的权限        if (requestUrl.equals(permission.getUrl())) {            //据url获取对应的角色列表            List<String> roles = permissionMapper.selectRoleCodeByUrl(permission.getId());            // 保留该url对应角色权限信息,将role返回            return SecurityConfig.createList(roles.toArray(new String[roles.size()]));        }    }    // 如果数据中没有找到相应url资源则为非法拜访,要求用户登录再进行操作    return SecurityConfig.createList("role_login");}@Overridepublic Collection<ConfigAttribute> getAllConfigAttributes() {    return null;}@Overridepublic boolean supports(Class<?> aClass) {    return FilterInvocation.class.isAssignableFrom(aClass);}

}

11、未登录和未受权的两种解决
/**

  • 当未登录或者token生效拜访接口时,自定义的返回后果
  • Created by macro on 2018/5/14.
    */

@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {

@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {    response.setCharacterEncoding("UTF-8");    response.setContentType("application/json");    response.getWriter().println("你还没登录哦");    response.getWriter().flush();}

}

12、没得权限
/**

  • 当拜访接口没有权限时,自定义的返回后果
  • Created by macro on 2018/4/26.
    */

@Component
public class RestfulAccessDeniedHandler implements AccessDeniedHandler {

@Overridepublic void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {    httpServletResponse.setCharacterEncoding("UTF-8");    httpServletResponse.setContentType("application/json");    httpServletResponse.getWriter().println("你没有权限哦");    httpServletResponse.getWriter().flush();}

}

13、入门小结,前面将会围绕security 的各种过滤器去进行进一步的剖析和学习