赞
踩
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 版权所有,并保留所有权利。