赞
踩
首先添加依赖 spring-boot-starter-security
然后之后每次启动项目之后,访问任何的请求都会要求输入密码才能请求。(如下)
在没有配置的情况下,默认用户名为 user ,密码在控制台中查找(如下)。
添加安全访问的配置文件如下。
- @Service
- public class UserDetailsServiceImpl implements UserDetailsService {
- @Autowired
- public UserMapper userMapper;
-
- @Override
- public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
- QueryWrapper<User> queryWrapper = new QueryWrapper<>();
- queryWrapper.eq("username", username);
- User user = userMapper.selectOne(queryWrapper);
- if(user == null)
- return (UserDetails) new RuntimeException("用户不存在!");
- return new UserDetailsImpl(user);
- }
- }
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- public class UserDetailsImpl implements UserDetails {
- private User user;
-
- @Override
- public Collection<? extends GrantedAuthority> getAuthorities() {
- return null;
- }
-
- @Override
- public String getPassword() {
- return user.getPasswd();
- }
-
- @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;
- }
- }
- @Configuration
- @EnableWebSecurity
- public class SecurityConfig extends WebSecurityConfigurerAdapter {
-
- @Bean
- public PasswordEncoder passwordEncoder() {
- return new BCryptPasswordEncoder();
- }
-
- }
以上配置添加之后即可正常使用数据库中的密码进行验证。前提是userMapper可以正常使用,进行查找用户。
如果数据库中的密码没有加密,可以通过测试类将密码进行加密,然后用加密之后的字符串与数据库中的数据进行替换即可。(如下)
- @SpringBootTest
- class TestJwtApplicationTests {
-
- @Test
- void contextLoads() {
- BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
- String encode = bCryptPasswordEncoder.encode("123456");
- System.out.println(encode);
- }
- }
- @Component
- public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
- @Autowired
- private UserMapper userMapper;
-
- @Override
- protected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException {
- String token = request.getHeader("Authorization");
-
- if (!StringUtils.hasText(token) || !token.startsWith("Bearer ")) {
- filterChain.doFilter(request, response);
- return;
- }
-
- token = token.substring(7);
-
- String userid;
- try {
- Claims claims = JwtUtil.parseJWT(token);
- userid = claims.getSubject();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
-
- User user = userMapper.selectById(Integer.parseInt(userid));
-
- if (user == null) {
- throw new RuntimeException("用户名未登录");
- }
-
- UserDetailsImpl loginUser = new UserDetailsImpl(user);
- UsernamePasswordAuthenticationToken authenticationToken =
- new UsernamePasswordAuthenticationToken(loginUser, null, null);
-
- SecurityContextHolder.getContext().setAuthentication(authenticationToken);
-
- filterChain.doFilter(request, response);
- }
- }
下面类里面的JWT_KEY的字符串是必须自己随机生成然后长度是有限制的如果后期报错记得修改长度。这个东西很重要,是你密码的加密规则。
- @Component
- public class JwtUtil {
- public static final long JWT_TTL = 60 * 60 * 1000L * 24 * 14; // 有效期14天
- public static final String JWT_KEY = "SDFGjhdsfalshdfHFdsjkdsfds121232131afasdfac";
-
- public static String getUUID() {
- return UUID.randomUUID().toString().replaceAll("-", "");
- }
-
- public static String createJWT(String subject) {
- JwtBuilder builder = getJwtBuilder(subject, null, getUUID());
- return builder.compact();
- }
-
- private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
- SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
- SecretKey secretKey = generalKey();
- long nowMillis = System.currentTimeMillis();
- Date now = new Date(nowMillis);
- if (ttlMillis == null) {
- ttlMillis = JwtUtil.JWT_TTL;
- }
-
- long expMillis = nowMillis + ttlMillis;
- Date expDate = new Date(expMillis);
- return Jwts.builder()
- .setId(uuid)
- .setSubject(subject)
- .setIssuer("sg")
- .setIssuedAt(now)
- .signWith(signatureAlgorithm, secretKey)
- .setExpiration(expDate);
- }
-
- public static SecretKey generalKey() {
- byte[] encodeKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
- return new SecretKeySpec(encodeKey, 0, encodeKey.length, "HmacSHA256");
- }
-
- public static Claims parseJWT(String jwt) throws Exception {
- SecretKey secretKey = generalKey();
- return Jwts.parserBuilder()
- .setSigningKey(secretKey)
- .build()
- .parseClaimsJws(jwt)
- .getBody();
- }
- }
然后修改之前的SecurityConfig配置类,里面的configure方法里面的.antMatchers里面追加的url是不需要验证就能进行使用的请求,比如登录注册等url请求的放开,需要的话可以一直追加。
- @Configuration
- @EnableWebSecurity
- public class SecurityConfig extends WebSecurityConfigurerAdapter {
- @Autowired
- private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
-
- @Bean
- public PasswordEncoder passwordEncoder() {
- return new BCryptPasswordEncoder();
- }
-
- @Bean
- @Override
- public AuthenticationManager authenticationManagerBean() throws Exception {
- return super.authenticationManagerBean();
- }
-
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- http.csrf().disable()
- .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
- .and()
- .authorizeRequests()
- .antMatchers("/user/login", "/user/account/register/").permitAll()
- .antMatchers(HttpMethod.OPTIONS).permitAll()
- .anyRequest().authenticated();
-
- http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
- }
- }
编写LoginServiceImpl,可以进行登录的验证,以及获取token并且返回给用户。之后访问其他请求的时候都需要验证该token验证身份,登录失败会报异常。
- @Service
- public class LoginServiceImpl{
- @Autowired
- // 认证管理器
- private AuthenticationManager authenticationManager;
-
- public Map<String, String> getToken(String username, String password) {
- // 将输入进来的username和password封装成一个密码加密过后的对象
- UsernamePasswordAuthenticationToken authenticationToken =
- new UsernamePasswordAuthenticationToken(username, password);
- // 该方法接收一个认证令牌对象,也就是认证请求作为参数,如果其中的信息匹配到目标账号,
- // 则该方法返回同一个认证令牌对象,不过其中被认证过程填充了更多的账号信息,比如授权和用户详情等。
- Authentication authenticate = authenticationManager.authenticate(authenticationToken);// 如果登录失败会自动报异常
- UserDetailsImpl loginUser = (UserDetailsImpl)authenticate.getPrincipal();
- User user = loginUser.getUser();
- String jwt = JwtUtil.createJWT(user.getId().toString());
- Map<String, String> map = new HashMap<>();
- map.put("error_message", "success");
- map.put("token", jwt);
-
- return map;
- }
- }
前端正常调用接口即可,将获取的token进行存储即可,用于,存储位置尽量安全。
通过以下操作可以直接从token中获取用户的信息,然后通过用户的信息进行验证并返回用户需要的信息。
- @Service
- public class InfoServiceImpl {
- @Autowired
- private UserMapper userMapper;
-
- public Map getInfoById() {
- Map data = new HashMap<>();
- UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
- UserDetailsImpl loginUser = (UserDetailsImpl)token.getPrincipal();
- User user = loginUser.getUser();
- user.setPasswd("");
- data.put("user", user);
- data.put("error_message", "success");
- return data;
- }
- }
前端的请求中需要加上token,注意Bearer后面要加一个空格。
然后即可正常使用。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。