欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringSecurity+Redis+Jwt實(shí)現(xiàn)用戶認(rèn)證授權(quán)

 更新時(shí)間:2024年07月09日 10:13:22   作者:MoCrane  
SpringSecurity是一個(gè)強(qiáng)大且靈活的身份驗(yàn)證和訪問控制框架,本文主要介紹了SpringSecurity+Redis+Jwt實(shí)現(xiàn)用戶認(rèn)證授權(quán),具有一定的參考價(jià)值,感興趣的可以了解一下

介紹

Spring Security是一個(gè)強(qiáng)大且靈活的身份驗(yàn)證和訪問控制框架,用于Java應(yīng)用程序。它是基于Spring框架的一個(gè)子項(xiàng)目,旨在為應(yīng)用程序提供安全性。

Spring Security致力于為Java應(yīng)用程序提供認(rèn)證授權(quán)功能。開發(fā)者可以輕松地為應(yīng)用程序添加強(qiáng)大的安全性,以滿足各種復(fù)雜的安全需求。

SpringSecurity完整流程

  • JwtAuthenticationTokenFilter:這里是我們自己定義的過(guò)濾器,主要負(fù)責(zé)放行不攜帶token的請(qǐng)求(如注冊(cè)或登錄請(qǐng)求),并對(duì)攜帶token的請(qǐng)求設(shè)置授權(quán)信息
  • UsernamePasswordAuthenticationFilter:負(fù)責(zé)處理我們?cè)诘顷戫?yè)面填寫了用戶名密碼后的登陸請(qǐng)求。入門案例的認(rèn)證工作主要由它負(fù)責(zé)
  • ExceptionTranslationFilter:處理過(guò)濾器鏈中拋出的任何AccessDeniedException和AuthenticationException
  • FilterSecurityInterceptor:負(fù)責(zé)權(quán)限校驗(yàn)的過(guò)濾器。

一般認(rèn)證工作流程

Authentication接口:它的實(shí)現(xiàn)類表示當(dāng)前訪問系統(tǒng)的用戶,封裝了用戶相關(guān)信息。

AuthenticationManager接口:定義了認(rèn)證Authentication的方法

UserDetailsService接口:加載用戶特定數(shù)據(jù)的核心接口。里面定義了一個(gè)根據(jù)用戶名查詢用戶信息的方法。

UserDetails接口:提供核心用戶信息。通過(guò)UserDetailsService根據(jù)用戶名獲取處理的用戶信息要封裝成UserDetails對(duì)象返回。然后將這些信息封裝到Authentication對(duì)象中。

數(shù)據(jù)庫(kù)

數(shù)據(jù)庫(kù)的采用**RBAC權(quán)限模型(基于角色的權(quán)限控制)**進(jìn)行設(shè)計(jì)。

RBAC至少需要三張表:用戶表–角色表–權(quán)限表(多對(duì)多的關(guān)系比較合理)

  • 用戶表(user):存儲(chǔ)用戶名、密碼等基礎(chǔ)信息,進(jìn)行登錄校驗(yàn)
  • 角色表(role):對(duì)用戶的角色進(jìn)行分配
  • 權(quán)限表(menu):存儲(chǔ)使用不同功能所需的權(quán)限

注冊(cè)流程

配置匿名訪問

在配置類中允許注冊(cè)請(qǐng)求可以匿名訪問

編寫實(shí)現(xiàn)類

registerDTO中存在字符串roleId和實(shí)體類user,先取出user判斷是否存在相同手機(jī)號(hào)。若該手機(jī)號(hào)沒有注冊(cè)過(guò)用戶,對(duì)密碼進(jìn)行加密后即可將用戶存入數(shù)據(jù)庫(kù)。

創(chuàng)建register方法映射,保存用戶的同時(shí)也要將roleId一并存入關(guān)系表中,使用戶獲得對(duì)應(yīng)角色。如下圖。

	@Override
    public Result register(RegisterDTO registerDTO) {
        // 獲取Map中的數(shù)據(jù)
        User user = registerDTO.getUser();
        String roleId = registerDTO.getRoleId();
        // 判斷是否存在相同手機(jī)號(hào)
        User dataUser = lambdaQuery()
                .eq(User::getUserPhone, user.getUserPhone()).one();
        if (!Objects.isNull(dataUser)) {
            return Result.fail("該手機(jī)號(hào)已注冊(cè)過(guò)用戶,請(qǐng)勿重復(fù)注冊(cè)");
        }
        // 密碼加密
        user.setUserPassword(passwordEncoder
                .encode(user.getUserPassword()));
        // 將用戶及對(duì)應(yīng)角色存入數(shù)據(jù)庫(kù)
        save(user);
        userMapper.register(user.getUserPhone(), roleId);

        return Result.ok("注冊(cè)成功");
    }

登錄流程

配置匿名訪問

在配置類中允許登錄請(qǐng)求可以匿名訪問

調(diào)用UserDetailsServiceImpl

登錄流程一般對(duì)應(yīng)認(rèn)證工作流程

	@Resource
    private AuthenticationManager authenticationManager;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private UserMapper userMapper;
    @Override
    public Result login(User user) {
        //AuthenticationManager 進(jìn)行用戶認(rèn)證,校驗(yàn)手機(jī)號(hào)和密碼是否正確
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserPhone(), user.getUserPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        //認(rèn)證失敗給出提示
        if (Objects.isNull(authenticate)) {
            throw new RuntimeException("用戶名或密碼錯(cuò)誤");
        }
        //認(rèn)證通過(guò),生成jwt并返回
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        String userId = loginUser.getUser().getUserId();
        String jwtToken = JwtUtil.createToken(userId);
        Map<String, String> map = new HashMap<>();

        stringRedisTemplate.opsForValue()
                .set(LOGIN_CODE_KEY + userId, JSONUtil.toJsonStr(loginUser));
        map.put("token", jwtToken);

        return Result.ok(map);
    }

先看這段代碼: UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserPhone(), user.getUserPassword());這里先用用戶手機(jī)號(hào)和密碼生成UsernamePasswordAuthenticationToken

再看這段代碼:Authentication authenticate = authenticationManager.authenticate(authenticationToken);利用authenticate調(diào)用自定義實(shí)現(xiàn)類UserDetailsServiceImpl,根據(jù)用戶名判斷用戶是否存在(對(duì)應(yīng)認(rèn)證流程的1、2、3、4)

實(shí)現(xiàn)UserDetailsServiceImpl

由于試下的是UserDetailsService接口,所以必須實(shí)現(xiàn)其方法loadUserByUsername(根據(jù)用戶名查詢數(shù)據(jù)庫(kù)是否存在)這里我傳入的是手機(jī)號(hào)。數(shù)據(jù)庫(kù)中若存在用戶,則返回UserDetails對(duì)象(這里的權(quán)限信息暫且不看,對(duì)應(yīng)認(rèn)證流程的5、5.1、5.2、6)

UserDetails對(duì)象返回后,authenticate方法會(huì)默認(rèn)通過(guò)PasswordEncoder比對(duì)UserDetails與Authentication的密碼是否相同。因?yàn)閁serDetails是通過(guò)自定義實(shí)現(xiàn)類從數(shù)據(jù)庫(kù)中查詢出的user對(duì)象,而Authentication相當(dāng)于是用戶輸入的用戶名和密碼,也就可以理解為通過(guò)前面自定義實(shí)現(xiàn)類利用用戶名查詢到用戶后,再看這個(gè)用戶的密碼是否正確。如果用戶名或密碼不正確,authenticate將會(huì)為空,則拋出異常信息。(對(duì)應(yīng)認(rèn)證流程的7)

由于這里的登錄流程不涉及8,9,10,所以不再敘述。

在剩下的代碼中我們利用用userId生成了jwt的令牌token,將其存入Redis中并返回token給前端。

登出流程

編寫過(guò)濾器

除login、register請(qǐng)求外的所有請(qǐng)求都需要攜帶token才能訪問,因此需要設(shè)計(jì)token攔截器代碼,如下。

對(duì)于不攜帶token的請(qǐng)求(如登錄/注冊(cè))直接放行;對(duì)于攜帶token的請(qǐng)求先判斷該用戶是否登錄,即redis中是否存在相關(guān)信息,若存在,將用戶授權(quán)信息存入SecurityContextHolder,方便用戶授權(quán),最后直接放行。

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 獲取token
        String token = request.getHeader("token");
        if (!StringUtils.hasText(token)) {
            // 沒有token,放行
            filterChain.doFilter(request, response);
            return;
        }
        // 解析token
        String userId = null;
        try {
            userId = JwtUtil.parseJwt(token);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("token非法:" + e);
        }
        // 從redis中獲取用戶信息
        String userJson = stringRedisTemplate
                .opsForValue().get(LOGIN_CODE_KEY + userId);
        LoginUser loginUser = JSONUtil.toBean(userJson, LoginUser.class);
        if (Objects.isNull(loginUser)) {
            throw new RuntimeException("用戶未登錄");
        }
        // 存入SecurityContextHolder,設(shè)置用戶授權(quán)信息
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        // 放行
        filterChain.doFilter(request, response);
    }
}

此外,還需將token攔截器設(shè)置在過(guò)濾器UsernamePasswordAuthenticationFilter的前面。

編寫實(shí)現(xiàn)類

	@Override
    public Result logout() {
        // 獲取SecurityContextHolder中的用戶id
        UsernamePasswordAuthenticationToken authentication =
                (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        String userId = loginUser.getUser().getUserId();

        // 刪除redis中的值
        stringRedisTemplate
                .delete(LOGIN_CODE_KEY + userId);
        return Result.ok("注銷成功");
    }

獲取SecurityContextHolder中的用戶id后,刪除redis中存儲(chǔ)的值,即登出成功。

授權(quán)流程

確保實(shí)現(xiàn)類正確編寫:

@Data
@NoArgsConstructor
public class LoginUser implements UserDetails {
    private User user;

    private List<String> permissions;

    public LoginUser(User user, List<String> permissions) {
        this.user = user;
        this.permissions = permissions;
    }

    @JsonIgnore
    private List<SimpleGrantedAuthority> authorities;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        if (authorities != null) {
            return authorities;
        }
        // 把permissions中String類型的權(quán)限信息封裝成SimpleGrantedAuthority對(duì)象
        authorities = permissions.stream()
                .map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
        return authorities;
    }

    @Override
    public String getPassword() {
        return user.getUserPassword();
    }

    @Override
    public String getUsername() {
        return user.getUserName();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

在token攔截器中,我們添加了這段代碼。

// 存入SecurityContextHolder,設(shè)置用戶授權(quán)信息
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

這樣非登錄/注冊(cè)請(qǐng)求都會(huì)被設(shè)置授權(quán)信息。

為對(duì)應(yīng)接口添加注解@PreAuthorize,就會(huì)檢驗(yàn)該請(qǐng)求是否存在相關(guān)請(qǐng)求。

完整代碼

config類

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
    @Resource
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    @Resource
    private AccessDeniedHandlerImpl accessDeniedHandler;
    @Resource
    private AuthenticationEntryPointImpl authenticationEntryPoint;

    @Bean
    public PasswordEncoder passwordEncoder() {
        // 實(shí)例化PasswordEncoder
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                //關(guān)閉csrf
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/user/login", "/user/register").anonymous()
                .anyRequest().authenticated();
        // 添加過(guò)濾器
        http
                .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        // 配置異常處理器
        http
                .exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint)
                .accessDeniedHandler(accessDeniedHandler);
        // 允許跨域
        http.cors();
        return http.build();
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        // 配置身份驗(yàn)證管理器
        return authenticationConfiguration.getAuthenticationManager();
    }

}

controller類

@RestController
@RequestMapping("/user")
public class UserController {
    @Resource
    private IUserService userService;
    @PostMapping("/login")
    public Result login(@RequestBody User user) {
        return userService.login(user);
    }

    @GetMapping("/logout")
    public Result logout() {
        return userService.logout();
    }

    @PostMapping("/register")
    public Result register(@RequestBody RegisterDTO registerDTO) {
        return userService.register(registerDTO);
    }

}

dto類

@Data
@NoArgsConstructor
@AllArgsConstructor
public class RegisterDTO {
    private User user;
    private String roleId;
}
/**
 * @author modox
 * @date 2023年6月1日
 * @description 封裝結(jié)果后返回
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {

    public static final Integer SUCCESS_CODE = 200;     // 訪問成功狀態(tài)碼
    public static final Integer TOKEN_ERROR = 400;      // Token錯(cuò)誤狀態(tài)碼
    public static final Integer ERROR_CODE = 500;       // 訪問失敗狀態(tài)碼
    private Integer status;                               // 狀態(tài)碼
    private String msg;                                 // 提示消息
    private Object data = null;

    public Result(Integer status, String msg) {
        this.status = status;
        this.msg = msg;
    }

    public static Result ok(Integer status,String msg,Object data){
        return new Result(status,msg,data);
    }

    public static Result ok(String msg,Object data){
        return new Result(SUCCESS_CODE,msg,data);
    }

    public static Result ok(Object data){
        return new Result(SUCCESS_CODE,"操作成功",data);
    }

    public static Result ok(){
        return new Result(SUCCESS_CODE,"操作成功",null);
    }

    public static Result fail(Integer status,String msg){
        return new Result(status,msg);
    }

    public static Result fail(String msg){
        return new Result(ERROR_CODE,msg);
    }

    public static Result fail(){
        return new Result(ERROR_CODE,"操作失敗");
    }

    public static Map<String,Object> ok(Map<String,Object> map){
        map.put("status",SUCCESS_CODE);
        map.put("msg","查詢成功");
        return map;
    }

    public static Map<String,Object> ok(PageInfo pageInfo){
        Map<String,Object> map = new HashMap<>();
        map.put("status",SUCCESS_CODE);
        map.put("msg","查詢成功");
        map.put("count",pageInfo.getTotal());
        map.put("data",pageInfo.getList());
        return map;
    }
}

entity類

UserDetails的實(shí)現(xiàn)類

@Data
@NoArgsConstructor
public class LoginUser implements UserDetails {
    private User user;

    private List<String> permissions;

    public LoginUser(User user, List<String> permissions) {
        this.user = user;
        this.permissions = permissions;
    }

    @JsonIgnore
    private List<SimpleGrantedAuthority> authorities;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        if (authorities != null) {
            return authorities;
        }
        // 把permissions中String類型的權(quán)限信息封裝成SimpleGrantedAuthority對(duì)象
        authorities = permissions.stream()
                .map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
        return authorities;
    }

    @Override
    public String getPassword() {
        return user.getUserPassword();
    }

    @Override
    public String getUsername() {
        return user.getUserName();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName(value = "grd_menu")
public class Menu {
    @TableId
    private String menuId;
    private String menuName;
    private String menuPerms;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName(value = "grd_user")
public class User {
    @TableId(type = IdType.ASSIGN_ID)
    private String userId;
    private String userName;
    private Integer userSex;
    private String userPhone;
    private String userPassword;
    private String userSchool;
    private Byte[] userImage;
}

filter類

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 獲取token
        String token = request.getHeader("token");
        if (!StringUtils.hasText(token)) {
            // 沒有token,放行
            filterChain.doFilter(request, response);
            return;
        }
        // 解析token
        String userId = null;
        try {
            userId = JwtUtil.parseJwt(token);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("token非法:" + e);
        }
        // 從redis中獲取用戶信息
        String userJson = stringRedisTemplate
                .opsForValue().get(LOGIN_CODE_KEY + userId);
        LoginUser loginUser = JSONUtil.toBean(userJson, LoginUser.class);
        if (Objects.isNull(loginUser)) {
            throw new RuntimeException("用戶未登錄");
        }
        // 存入SecurityContextHolder,設(shè)置用戶授權(quán)信息
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        // 放行
        filterChain.doFilter(request, response);
    }
}

handler類

@Component
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        Result result = new Result(HttpStatus.FORBIDDEN.value(), "您的權(quán)限不足");
        String json = JSONUtil.toJsonStr(result);
        // 處理異常
        WebUtils.renderString(response, json);
    }
}
@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        Result result = new Result(HttpStatus.UNAUTHORIZED.value(), "用戶認(rèn)證失敗");
        String json = JSONUtil.toJsonStr(result);
        // 處理異常
        WebUtils.renderString(response, json);
    }
}

service實(shí)現(xiàn)類

@Service
public class UserDetailsServiceImpl extends ServiceImpl<UserMapper, User>  implements UserDetailsService {
    @Resource
    private MenuMapper menuMapper;
    @Override
    public UserDetails loadUserByUsername(String userPhone) throws UsernameNotFoundException {
        //根據(jù)用戶名查詢用戶信息
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("user_phone", userPhone);
        User user = getOne(wrapper);
        //若數(shù)據(jù)庫(kù)中不存在用戶
        if (Objects.isNull(user)) {
            throw new RuntimeException("該手機(jī)號(hào)未注冊(cè)");
        }
        // 根據(jù)用戶查詢權(quán)限信息 添加到LoginUser中
        List<String> list = menuMapper.selectPermsByUserPhone(user.getUserPhone());
        // 封裝成UserDetails對(duì)象返回
        return new LoginUser(user, list);
    }
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Resource
    private AuthenticationManager authenticationManager;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private UserMapper userMapper;
    @Override
    public Result login(User user) {
        //AuthenticationManager 進(jìn)行用戶認(rèn)證,校驗(yàn)手機(jī)號(hào)和密碼是否正確
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserPhone(), user.getUserPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        //認(rèn)證失敗給出提示
        if (Objects.isNull(authenticate)) {
            throw new RuntimeException("用戶名或密碼錯(cuò)誤");
        }
        //認(rèn)證通過(guò),生成jwt并返回
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        String userId = loginUser.getUser().getUserId();
        String jwtToken = JwtUtil.createToken(userId);
        Map<String, String> map = new HashMap<>();

        stringRedisTemplate.opsForValue()
                .set(LOGIN_CODE_KEY + userId, JSONUtil.toJsonStr(loginUser));
        map.put("token", jwtToken);

        return Result.ok(map);
    }

    @Override
    public Result logout() {
        // 獲取SecurityContextHolder中的用戶id
        UsernamePasswordAuthenticationToken authentication =
                (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        String userId = loginUser.getUser().getUserId();

        // 刪除redis中的值
        stringRedisTemplate
                .delete(LOGIN_CODE_KEY + userId);
        return Result.ok("注銷成功");
    }

    @Override
    public Result register(RegisterDTO registerDTO) {
        // 獲取Map中的數(shù)據(jù)
        User user = registerDTO.getUser();
        String roleId = registerDTO.getRoleId();
        // 判斷是否存在相同手機(jī)號(hào)
        User dataUser = lambdaQuery()
                .eq(User::getUserPhone, user.getUserPhone()).one();
        if (!Objects.isNull(dataUser)) {
            return Result.fail("該手機(jī)號(hào)已注冊(cè)過(guò)用戶,請(qǐng)勿重復(fù)注冊(cè)");
        }
        // 密碼加密
        user.setUserPassword(passwordEncoder
                .encode(user.getUserPassword()));
        // 將用戶及對(duì)應(yīng)角色存入數(shù)據(jù)庫(kù)
        save(user);
        userMapper.register(user.getUserPhone(), roleId);

        return Result.ok("注冊(cè)成功");
    }
}

utils類

public class JwtUtil {
    // token失效:24小時(shí)
    public static final String token = "token";
    public static final long EXPIPE = 1000 * 60 * 60 * 10;
    public static final String APP_SECRET = "modox@ukc8BDbRigUDaY6pZFfWus2jZWLPHO";

    /**
     * 根據(jù)傳入的用戶Id生成token
     * @param userId
     * @return JWT規(guī)則生成的token
     */
    public static String createToken(String userId) {
        String JwtToken = Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")
                .setSubject("grd_user")
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIPE))
                .claim("userId", userId)
                .signWith(SignatureAlgorithm.HS256, APP_SECRET)
                .compact();

        return JwtToken;
    }

    /**
     * 驗(yàn)證token是否有效
     * @param jwtToken token字符串
     * @return 如果token有效返回true,否則false
     */
    public static boolean checkToken(String jwtToken) {
        try {
            if (!StringUtils.hasText(jwtToken))
                return false;
            Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 根據(jù)token獲取User信息
     * @param jwtToken token字符串
     * @return 解析token獲得的user對(duì)象
     */
    public static String parseJwt(String jwtToken) {
        //驗(yàn)證token
        if (checkToken(jwtToken)) {
            Claims claims = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken).getBody();
            return claims.get("userId").toString();
        }else {
            throw new RuntimeException("超時(shí)或不合法token");
        }
    }
}

public class RedisConstants {
    public static final String LOGIN_CODE_KEY = "login:code:";
    public static final Long LOGIN_CODE_TTL = 2L;
    public static final String LOGIN_USER_KEY = "login:token:";
    public static final Long LOGIN_USER_TTL = 36000L;
}
public class WebUtils {
    /**
     * 將字符串渲染到客戶端
     * @param response
     * @param string
     * @return
     */
    public static String renderString(HttpServletResponse response, String string) {
        try {
            response.setStatus(200);
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            response.getWriter().print(string);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

到此這篇關(guān)于SpringSecurity+Redis+Jwt實(shí)現(xiàn)用戶認(rèn)證授權(quán)的文章就介紹到這了,更多相關(guān)SpringSecurity+Redis+Jwt認(rèn)證授權(quán)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

最新評(píng)論