赞
踩
SpringSecurity与JWT整合
数据库基于:SpringSecurity从数据库中获取用户信息进行验证
依赖:
<dependencies> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.21</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies>
application.properties:
spring.thymeleaf.cache=false
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springsecurity001?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
mybatis.mapper-locations=classpath:mapper/*.xml
启动类SecurityJwtApplication:
@SpringBootApplication
@MapperScan("com.blu.mapper")
public class SecurityJwtApplication {
public static void main(String[] args) {
SpringApplication.run(SecurityJwtApplication.class, args);
}
@Bean
public BCryptPasswordEncoder bcryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
}
MyUser:
@Data public class MyUser implements UserDetails { private Integer id; private String name; private String password; private List<MyRole> roles; @JsonIgnore @Override public Collection<? extends GrantedAuthority> getAuthorities() { return roles; } @JsonIgnore @Override public String getUsername() { return name; } @JsonIgnore @Override public boolean isAccountNonExpired() { return true; } @JsonIgnore @Override public boolean isAccountNonLocked() { return true; } @JsonIgnore @Override public boolean isCredentialsNonExpired() { return true; } @JsonIgnore @Override public boolean isEnabled() { return true; } }
MyRole:
@Data
public class MyRole implements GrantedAuthority {
private Integer id;
private String name;
@JsonIgnore
@Override
public String getAuthority() {
return name;
}
}
MyUserMapper:
public interface MyUserMapper {
MyUser findByName(String name);
}
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.blu.mapper.MyUserMapper"> <resultMap type="com.blu.entity.MyUser" id="myUserMap"> <id column="uid" property="id"></id> <result column="uname" property="name"></result> <result column="password" property="password"></result> <collection property="roles" ofType="com.blu.entity.MyRole"> <id column="rid" property="id" /> <result column="rname" property="name" /> </collection> </resultMap> <select id="findByName" parameterType="String" resultMap="myUserMap"> select u.id uid,u.name uname,u.password,r.id rid,r.name rname from user u,role r,role_user ur where u.name = #{name} and ur.user_id = u.id and ur.role_id = r.id </select> </mapper>
UserService:
public interface UserService extends UserDetailsService {
}
UserServiceImpl:
@Service
public class UserServiceImpl implements UserService {
@Autowired
private MyUserMapper myUserMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
MyUser myUser = myUserMapper.findByName(username);
return myUser;
}
}
JwtLoginFilter:
public class JwtLoginFilter extends AbstractAuthenticationProcessingFilter { public JwtLoginFilter(String defaultFilterProcessesUrl, AuthenticationManager authenticationManager) { super(new AntPathRequestMatcher(defaultFilterProcessesUrl)); setAuthenticationManager(authenticationManager); } /** * 从登录参数json数据中获取用户名密码,然后调用AuthenticationManager.authenticate()方法进行校验。 */ @Override public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse resp) throws AuthenticationException, IOException, ServletException { //将用户传的json数据转为user对象 MyUser user = new ObjectMapper().readValue(req.getInputStream(),MyUser.class); return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(),user.getPassword())); } /** * 校验成功 */ @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { Collection<? extends GrantedAuthority> authorities = authResult.getAuthorities(); StringBuffer sb = new StringBuffer(); for (GrantedAuthority authority : authorities) { sb.append(authority.getAuthority()).append(","); } String jwt = Jwts.builder() .claim("authorities", sb) .setSubject(authResult.getName()) .setExpiration(new Date(System.currentTimeMillis() + 60 * 60 * 1000))//设置过期时间 .signWith(SignatureAlgorithm.HS512, "root@123")//设置加密方式,以及key .compact(); //设置登录成功后返回的信息 Map<String,String> map = new HashMap<>(); map.put("token",jwt); map.put("msg","登录成功"); response.setContentType("application/json;charset=utf-8"); PrintWriter writer = response.getWriter(); writer.write(new ObjectMapper().writeValueAsString(map)); writer.flush(); writer.close(); } /** * 校验失败 */ @Override protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException { Map<String,String> map = new HashMap<>(); map.put("msg","登录失败"); response.setContentType("application/json;charset=utf-8"); PrintWriter writer = response.getWriter(); writer.write(new ObjectMapper().writeValueAsString(map)); writer.flush(); writer.close(); } }
JwtFilter:
public class JwtFilter extends GenericFilterBean { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) servletRequest; //从请求头中获取token String jwtToken = req.getHeader("authorization"); Jws<Claims> jws = Jwts.parser().setSigningKey("root@123") .parseClaimsJws(jwtToken.replace("Bearer", "")); Claims claims = jws.getBody(); String username = claims.getSubject(); //获取角色 List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList((String) claims.get("authorities")); UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username,"",authorities); SecurityContextHolder.getContext().setAuthentication(token); filterChain.doFilter(servletRequest,servletResponse); } }
测试接口:
@RestController public class StringController { @GetMapping("hello") public String hello() { return "hello BLU!"; } @GetMapping("hi") public String hi() { return "hi everyone!"; } @GetMapping("admin") public String admin() { return "hello admin!"; } }
Security配置类:
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter{ @Autowired private UserServiceImpl userServiceImpl; @Autowired private BCryptPasswordEncoder bcryptPasswordEncoder; @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers(HttpMethod.GET,"/hi").permitAll() .antMatchers("/hello").hasRole("vip1") .antMatchers("/admin").hasRole("admin"); http.formLogin().loginPage("/tologin") .usernameParameter("name") .passwordParameter("password") .loginProcessingUrl("/login"); http.csrf().disable(); http.addFilterBefore(new JwtLoginFilter("/login",authenticationManager()), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(new JwtFilter(),UsernamePasswordAuthenticationFilter.class); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userServiceImpl).passwordEncoder(bcryptPasswordEncoder); } }
测试错误密码登录:
测试正确密码登录:
测试访问(有权限):
测试访问(无权限):
测试访问(错误token):
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。