新建用户表——users,并完成数据库增删查改
一、新建表
二、持久化映射,建立模型类,添加主键生成器
//指定生成器名称
@GeneratedValue(generator = "uuid2" )
@GenericGenerator(name = "uuid2", strategy = "org.hibernate.id.UUIDGenerator" )
三、建立Dao层
package edu.ynmd.cms.dao;
import edu.ynmd.cms.model.Users;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import javax.websocket.server.PathParam;
import java.util.List;
public interface UsersDao extends JpaRepository {
@Query("select u from Users u where u.username=:username and u.pass=:pass")
List getUsersByUsernameAndPass(@Param("username")String username, @Param("pass") String pass);
}
四、配置service层
//用户表
Users saveUser(Users users);
boolean deleteUser(String id);
Users getUser(String id);
Users getUserByUserNameAndPass(String username,String pass);
- 在ManageServiceImpl添加方法具体实现
//*****************************用户表增删查改开始*********************************
@Override
public Users saveUser(Users users) {
try {
return usersDao.save(users);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
@Override
public boolean deleteUser(String id) {
try {
usersDao.deleteById(id);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
@Override
public Users getUser(String id) {
Optional temp=usersDao.findById(id);
return temp.isPresent()?temp.get():null;
}
@Override
public Users getUserByUserNameAndPass(String username, String pass) {
List ul=usersDao.getUsersByUsernameAndPass(username,pass);
if(ul.size()>0){
return ul.get(0);
}
return null;
}
JWT框架的搭建
一、添加Maven依赖
org.springframework.boot
spring-boot-starter-security
io.jsonwebtoken
jjwt
0.7.0
二、编写JwtUtil工具类(生成token,解析token,校验token)
package edu.ynmd.cms.tools;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class JwtUtil {
private static final Logger logger= LoggerFactory.getLogger(JwtUtil.class);
public static final long EXPIRATION_TIME=60*60*1000;// 令牌环有效期
public static final String SECRET="abc123456def";//令牌环密钥
public static final String TOKEN_PREFIX="Bearer";//令牌环头标识
public static final String HEADER_STRING="Passport";//配置令牌环在http heads中的键值
public static final String ROLE="ROLE";//自定义字段-角色字段
//生成令牌环
public static String generateToken(String userRole,String userid){
HashMap map=new HashMap<>();
map.put(ROLE,userRole);
map.put("userid",userid);
String jwt= Jwts.builder()
.setClaims(map)
.setExpiration(new Date(System.currentTimeMillis()+EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS512,SECRET)
.compact();
return TOKEN_PREFIX+" "+jwt;
}
//生成令牌环
public static String generateToken(String userRole,String userid,long exprationtime){
HashMap map=new HashMap<>();
map.put(ROLE,userRole);
map.put("userid",userid);
String jwt= Jwts.builder()
.setClaims(map)
.setExpiration(new Date(System.currentTimeMillis()+exprationtime))
.signWith(SignatureAlgorithm.HS512,SECRET)
.compact();
return TOKEN_PREFIX+" "+jwt;
}
//令牌环校验
public static Map validateTokenAndGetClaims(HttpServletRequest request){
String token=request.getHeader(HEADER_STRING);
if(token==null){
throw new TokenValidationException("Missing Token");
}
else{
Map body=Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token.replace(TOKEN_PREFIX,""))
.getBody();
return body;
}
}
static class TokenValidationException extends RuntimeException{
public TokenValidationException(String msg){
super(msg);
}
}
}
三、集成JWT filter(拦截器/过滤器)——建立filter包
package edu.ynmd.cms.filter;
import edu.ynmd.cms.tools.JwtUtil;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import static edu.ynmd.cms.tools.JwtUtil.ROLE;
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private static final PathMatcher pathmatcher = new AntPathMatcher();
private String[] protectUrlPattern = {"/manage/**", "/member/**", "/auth/**"}; //那些请求需要进行安全校验
public JwtAuthenticationFilter() {
}
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
//是不是可以在这里做多种方式登录呢
try {
if (isProtectedUrl(httpServletRequest)) {
Map claims = JwtUtil.validateTokenAndGetClaims(httpServletRequest);
String role = String.valueOf(claims.get(ROLE));
String userid = String.valueOf(claims.get("userid"));
//最关键的部分就是这里, 我们直接注入了
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(
userid, null, Arrays.asList(() -> role)
));
}
} catch (Exception e) {
e.printStackTrace();
httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
return;
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
//是否是保护连接
private boolean isProtectedUrl(HttpServletRequest request) {
boolean flag = false;
for (int i = 0; i < protectUrlPattern.length; i++) {
if (pathmatcher.match(protectUrlPattern[i], request.getServletPath())) {
return true;
}
}
return false;
}
}
四、配置JWT config类
package edu.ynmd.cms.config;
import edu.ynmd.cms.filter.JwtAuthenticationFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.cors() //允许跨域访问
.and()
.authorizeRequests()
.antMatchers("/").authenticated() //配置那些url需要进行校验--所有请求都需要校验"/"
.antMatchers("/public/**").permitAll() //那些请求不需要校验
.anyRequest().authenticated() //自定义校验类
.and()
.addFilterBefore(new JwtAuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class)
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)//关闭session
;
}
}
五、添加Action注解——在AdminAction添加
@CrossOrigin
@RestController
@PreAuthorize("hasAuthority('admin')") //配置角色,拥有该角色的用户方可访问
@RequestMapping("/manage")
六、登录Action——在PublicAction添加
//用户登录方法
@PostMapping("/login")
@ResponseBody
public HashMap login(
@RequestBody Account account) throws IOException {
Users u=manageService.getUserByUserNameAndPass(account.username,account.password);
//if(account.username.equals("admin")&&account.password.equals("123456")){
if(u!=null){
//String jwt= JwtUtil.generateToken("admin","123456789abc");
String jwt= JwtUtil.generateToken(u.getRoleid(),u.getUsersid());
return new HashMap(){{
put("msg","ok");
put("token",jwt);
put("role",u.getRoleid());
// put("role","admin");
}};
}
else {
//return new ResponseEntity(HttpStatus.UNAUTHORIZED);
return new HashMap(){{
put("msg","error");
put("token","error");
}};
}
}
public static class Account{
public String username;
public String password;
}
七、token令牌环,访问需要验证的资源,新建service工具类
- 在tools中添加isNullOrSpace方法进行判断
public static boolean isNullOrSpace(String value){
if(value==null){
return true;
}
else {
if(value.equals("")){
return true;
}
else {
return false;
}
}
}
String getCurrentUserId();
String getCurrentRole();
- 在ManageServiceImpl添加方法具体实现
//获取当前登录用的的Id
@Override
public String getCurrentUserId() {
String userid= (String) SecurityContextHolder.getContext().getAuthentication() .getPrincipal();
if(Tools.isNullOrSpace(userid)){
return null;
}
else {
return userid;
}
}
//获取当前登录用户的角色
@Override
public String getCurrentRole() {
String role=null;
Collection authorities = (Collection) SecurityContextHolder.getContext().getAuthentication().getAuthorities();
for (GrantedAuthority authority : authorities) {
role = authority.getAuthority();
}
if(Tools.isNullOrSpace(role)){
return null;
}
else{
return role;
}
}
八、识别token令牌环信息——在AdminAction添加
@GetMapping("testSecurityResource")
@ResponseBody
public String testSecurityResource() throws Exception{
String userid=manageService.getCurrentUserId();
String role=manageService.getCurrentRole();
return "受保护的资源,当前用户的id是"+userid+"当前用户的角色是"+role;
}
九、自动更新令牌环,新建AuthAction类
package edu.ynmd.cms.action;
import edu.ynmd.cms.tools.JwtUtil;
import edu.ynmd.cms.tools.Tools;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.HashMap;
//令牌环更新
@CrossOrigin
@RestController
@PreAuthorize("hasAuthority('admin')")
@RequestMapping("/auth")
public class AuthAction {
//更新令牌环信息
@GetMapping("refreshToken")
@ResponseBody
public HashMap refreshToken( HttpServletRequest request){
String role=null;
Collection authorities = (Collection) SecurityContextHolder.getContext().getAuthentication().getAuthorities();
for (GrantedAuthority authority : authorities) {
role = authority.getAuthority();
}
// UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication() .getPrincipal();
String userid= (String)SecurityContextHolder.getContext().getAuthentication() .getPrincipal();
if(Tools.isNullOrSpace(role)){
return new HashMap(){{
put("token","error");
}};
}
else{
String jwt="";
jwt= JwtUtil.generateToken(role,userid,60*60*1000);//一小时
HashMap m=new HashMap<>();
m.put("token",jwt);
return m;
}
}
//获取当前登录用户的角色
@GetMapping("getRole")
@ResponseBody
public HashMap getRoleByToken(){
String role="";
String userid="";
Collection authorities = (Collection) SecurityContextHolder.getContext().getAuthentication().getAuthorities();
for (GrantedAuthority authority : authorities) {
role = authority.getAuthority();
}
if(Tools.isNullOrSpace(role)){
return new HashMap(){{
put("role","error");
}};
}
else{
HashMap m=new HashMap<>();
m.put("role",role);
return m;
}
}
}
最后用postman进行测试
结果