精华内容
下载资源
问答
  • 主要为大家详细介绍了SpringBoot框架集成token实现登录校验功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • springboot基于token实现登录认证

    千次阅读 2020-08-12 15:20:03
    最近因为项目需求,需采用token的方式实现登录认证,而不再使用session的方式登录,因而采用springboot集成JWT生成token实现登录认证。 1.首先添加jwt所需jar包 <dependency> <groupId>io.jsonwebtoken...

    最近因为项目需求,需采用token的方式实现登录认证,而不再使用session的方式登录,因而采用springboot集成JWT生成token实现登录认证。

    1.首先添加jwt所需jar包

    <dependency>
          <groupId>io.jsonwebtoken</groupId>
          <artifactId>jjwt</artifactId>
          <version>0.7.0</version>
    </dependency>
    

    2.接下来根据需要建一个工具类JwtUtils。

    /**
     * jwt工具类
     */
    @ConfigurationProperties(prefix = "dingapp.jwt")
    @Component
    public class JwtUtils {
        private Logger logger = LoggerFactory.getLogger(getClass());
    
        private String secret;
        private long expire;
        private String header;
    
        /**
         * 生成jwt token
         */
        public String generateToken(String companyId,String userId,Long expireTime, YAMLUtils.SysType st) {
            Date nowDate = new Date();
            Long v = expire;
            if(expireTime != null){
                v = expireTime;
            }
            //过期时间
            Date expireDate = new Date(nowDate.getTime() + v * 1000);
            return Jwts.builder().claim("SysType",st.getType())
                    .setHeaderParam("typ", "JWT")
                    .setId(companyId)
                    .setSubject(userId)
                    .setIssuedAt(nowDate)
                    .setExpiration(expireDate)
                    .signWith(SignatureAlgorithm.HS512, secret)
                    .compact();
        }
        /**
         * 解析token  
         */
        public Claims getClaimByToken(String token) {
            try {
                return Jwts.parser()
                        .setSigningKey(secret)
                        .parseClaimsJws(token)
                        .getBody();
            }catch (Exception e){
                logger.debug("validate is token error ", e);
                return null;
            }
        }
    
        /**
         * token是否过期
         * @return  true:过期
         */
        public boolean isTokenExpired(Date expiration) {
            return expiration.before(new Date());
        }
    
        public String getSecret() {
            return secret;
        }
    
        public void setSecret(String secret) {
            this.secret = secret;
        }
    
        public long getExpire() {
            return expire;
        }
    
        public void setExpire(long expire) {
            this.expire = expire;
        }
    
        public String getHeader() {
            return header;
        }
    
        public void setHeader(String header) {
            this.header = header;
        }
    

    这个工具类是通过jwt生成token以及对token的解析,这里对token设置了过期时间,如果token解析不出或者说过期则会抛出异常。
    3.工具类写好后,可以在登录时验证完登录密码生成token并返回给前端。

        @PostMapping("/login")
        public ApiResult login(@RequestBody SysUser user, HttpServletRequest request) {
        	ApiResult result = new ApiResult();
            //多类型账号登陆
            SysUser userBySomeCase = userService.getUserByAcc(user);
            Integer landType = user.getType();
            SysUser u;
            u = new SysUser();
            u.setAccNum(user.getAccNum());
            u = userService.getUserByAcc(u);
            if(u != null && !Objects.equals(u.getPasswd(),CommonUtil.encryptPsw(user.getPasswd()))){
                    return result.failed("账号或密码错误");
                }
           }
           if(u == null){
               return result.failed("账号或密码错误");
            }
            SysUser data = u;
            //
            String token = jwtUtils.generateToken(null,u.getUserID()+"",null,YAMLUtils.SysType.SysType3);
            data.setToken(token1);
            return result.success(data, "登录成功");
        }
    

    4.当用户请求接口时会在header中携带token,后端会对所有接口在前置拦截器进行拦截,作用是对拿到的token进行解析,如果解析失败,会抛出SignatureException异常,如果解析成功,则不会拦截。

     @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
            String token = httpServletRequest.getHeader("token");
            if(StringUtils.isBlank(token )){
            	throw new IncorrectCredentialsException("请先登录");
            }
            final Claims claims = jwtUtils.getClaimByToken(token);
            if (claims == null || jwtUtils.isTokenExpired(claims.getExpiration())) {
                throw new IncorrectCredentialsException("token失效,请重新登录");
            }      
            return true;
        }
    

    5.可以对jwt进行全局配置。

    dingapp:
      jwt:
        # 加密秘钥
        secret: dfjlaer********
        # token有效时长,24小时,单位秒
        expire: 86400
        header: token`在这里插入代码片`
    

    总结:
    1.因为jwt生成token的无状态性,以及便于传输,构成非常简单,字节占用很小,它不需要在服务端保存
    会话信息, 所以它易于应用的扩展。
    2.但一旦拿到访问的token,就可直接访问到服务器,所以对于私钥的保护非常重要。

    展开全文
  • redis+token实现登录状态 /* * 登录后存储用户对象的redis函数 */ @RequestMapping(value = "/loginRedis",method=RequestMethod.POST) public AppResult loginRedis(UserInfo userInfo){ String uuid = ...
                                   redis+token实现登录状态
    
       /*
        * 登录后存储用户对象的redis函数
        */
        @RequestMapping(value = "/loginRedis",method=RequestMethod.POST)
        public AppResult loginRedis(UserInfo userInfo){
            String uuid = Utils.getUUID();
            String value = JSON.toJSONString(userInfo);
            stringRedisTemplate.opsForValue().set(uuid,value);
            //30分钟后自动退出
            stringRedisTemplate.expire(uuid,30, TimeUnit.MINUTES);
            return  AppResult.successData("token",uuid);
    
        }
    
        /*
         * 调用接口的时候的登录状态的授权
         */
        @RequestMapping(value = "/isLogin",method=RequestMethod.GET)
        @ResponseBody
        public UserInfo isLogin(@RequestParam("token") String token){
            String userInfoStr = stringRedisTemplate.opsForValue().get(token).toString();
            if (userInfoStr==""||userInfoStr==null){
                return null;
            }else {
                //刷新redis的值30分钟
                stringRedisTemplate.expire(token,30, TimeUnit.MINUTES);
               //返回登录的用户对象
                UserInfo userInfo =  JSON.parseObject(userInfoStr,UserInfo.class);
               return  userInfo;
            }
        }
    
    展开全文
  • jave web token实现登录验证 JWT JWT官网: https://jwt.io/ JWT(Java版)的github地址:https://github.com/jwtk/jjwt 什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放...

    jave web token实现登录验证

    JWT

    JWT官网: https://jwt.io/
    JWT(Java版)的github地址:https://github.com/jwtk/jjwt

    什么是JWT

    Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).**定义了一种简洁的,自包含的方法用于通信双方之间以JSON对象的形式安全的传递信息。**因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名。

    JWT请求流程

    img

    1. 用户使用账号和面发出post请求;
    2. 服务器使用私钥创建一个jwt;
    3. 服务器返回这个jwt给浏览器;
    4. 浏览器将该jwt串在请求头中像服务器发送请求;
    5. 服务器验证该jwt;
    6. 返回响应的资源给浏览器。

    JWT的主要应用场景

    身份认证在这种场景下,一旦用户完成了登陆,在接下来的每个请求中包含JWT,**可以用来验证用户身份以及对路由,服务和资源的访问权限进行验证。由于它的开销非常小,可以轻松的在不同域名的系统中传递,所有目前在单点登录(SSO)**中比较广泛的使用了该技术。 信息交换在通信的双方之间使用JWT对数据进行编码是一种非常安全的方式,由于它的信息是经过签名的,可以确保发送者发送的信息是没有经过伪造的。

    优点

    1.简洁(Compact): 可以通过URLPOST参数或者在HTTP header发送,因为数据量小,传输速度也很快
    2.自包含(Self-contained):负载中包含了所有用户所需要的信息,避免了多次查询数据库
    3.因为Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言的,原则上任何web形式都支持。
    4.不需要在服务端保存会话信息,特别适用于分布式微服务。

    `

    JWT的结构

    JWT是由三段信息构成的,将这三段信息文本用.连接一起就构成了JWT字符串。
    就像这样:
    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

    JWT包含了三部分:
    Header 头部(标题包含了令牌的元数据,并且包含签名和/或加密算法的类型)
    Payload 负载 (类似于飞机上承载的物品)
    Signature 签名/签证

    Header

    JWT的头部承载两部分信息:token类型和采用的加密算法。

    { 
      "alg": "HS256",
       "type": "JWT"
    } 
    

    声明类型:这里是jwt
    声明加密的算法:通常直接使用 HMAC SHA256

    加密算法是单向函数散列算法,常见的有MD5、SHA、HAMC。
    MD5(message-digest algorithm 5) (信息-摘要算法)缩写,广泛用于加密和解密技术,常用于文件校验。校验?不管文件多大,经过MD5后都能生成唯一的MD5值
    SHA (Secure Hash Algorithm,安全散列算法),数字签名等密码学应用中重要的工具,安全性高于MD5
    HMAC (Hash Message Authentication Code),散列消息鉴别码,基于密钥的Hash算法的认证协议。用公开函数和密钥产生一个固定长度的值作为认证标识,用这个标识鉴别消息的完整性。常用于接口签名验证

    Payload

    载荷就是存放有效信息的地方。
    有效信息包含三个部分
    1.标准中注册的声明
    2.公共的声明
    3.私有的声明

    标准中注册的声明 (建议但不强制使用) :

    iss: jwt签发者
    sub: 面向的用户(jwt所面向的用户)
    aud: 接收jwt的一方
    exp: 过期时间戳(jwt的过期时间,这个过期时间必须要大于签发时间)
    nbf: 定义在什么时间之前,该jwt都是不可用的.
    iat: jwt的签发时间
    jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

    公共的声明 :

    公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.

    私有的声明 :

    私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。

    Signature

    jwt的第三部分是一个签证信息
    这个部分需要base64加密后的headerbase64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。
    密钥secret是保存在服务端的,服务端会根据这个密钥进行生成token和进行验证,所以需要保护好。

    作者:意识流丶
    链接:https://www.jianshu.com/p/e88d3f8151db
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    Springboot集成JWT

    pom文件

    添加JWT依赖

    <dependency>
          <groupId>com.auth0</groupId>
          <artifactId>java-jwt</artifactId>
          <version>3.4.0</version>
    </dependency>
    

    自定义注解

    /**当使用@PassToken注解在接口/方法时调用,或者用于当做一个注解标识,可以通过调用接口时检查是否有该标识
    @Target:注解的作用目标
    @Target(ElementType.TYPE)——接口、类、枚举、注解
    @Target(ElementType.FIELD)——字段、枚举的常量
    @Target(ElementType.METHOD)——方法
    @Target(ElementType.PARAMETER)——方法参数
    @Target(ElementType.CONSTRUCTOR) ——构造函数
    @Target(ElementType.LOCAL_VARIABLE)——局部变量
    @Target(ElementType.ANNOTATION_TYPE)——注解
    @Target(ElementType.PACKAGE)——包
    
    @Retention:注解的保留位置
    RetentionPolicy.SOURCE:这种类型的Annotations只在源代码级别保留,编译时就会被忽略,在class字节码文件中不包含。
    RetentionPolicy.CLASS:这种类型的Annotations编译时被保留,默认的保留策略,在class文件中存在,但JVM将会忽略,运行时无法获得。
    RetentionPolicy.RUNTIME:这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用。
    @Document:说明该注解将被包含在javadoc中
    @Inherited:说明子类可以继承父类中的该注解
    **/
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface PassToken {
        boolean required() default true;
    }
    
    

    Token工具类

    定义一个token工具类,用于生成token或者验证token等方法

    @Component
    public class TokenHelp {
        @Autowired
        private UserService userService;
    
        public boolean tokenValidate(String token,boolean isAdmin){
                // 执行认证
                if (token == null) {
                    throw new RRException("无token,请重新登录");
                }
                // 获取 token 中的 user id
                String userId;
                try {
                    userId = JWT.decode(token).getAudience().get(0);
                } catch (JWTDecodeException j) {
                    throw new RRException("401");
                }
                UserEntity user = userService.getById(userId);
                //验证是否是管理员账号
                if(isAdmin){
                    if(!user.getUserName().equals(Constant.SUPER_ADMIN_NAME)){
                        throw new RRException("该操作需要有管理员权限");
                    }
                }
                if (user == null) {
                    throw new RRException("用户不存在,请重新登录");
                }
                // 验证 token
                JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
                try {
                    jwtVerifier.verify(token);
                } catch (JWTVerificationException e) {
                    throw new RRException("401");
                }
                return true;
        }
    
        public String getToken(UserEntity user) {
            String token="";
            //Algorithm.HMAC256():使用HS256生成token,密钥则是用户的密码,唯一密钥的话可以保存在服务端。
    	//withAudience()存入需要保存在token的信息,这里把用户ID存入token中
            token= JWT.create().withAudience(user.getId().toString())
                    .sign(Algorithm.HMAC256(user.getPassword()));
            return token;
        }
    }
    
    

    拦截器

    定义一个拦截器,拦截所有请求,如果有接口声明需要登录才访问,则拦截该请求进行token验证

    该类实现WebMvcConfigurer接口,重写拦截方法

    WebMvcConfigurer详解链接:https://blog.csdn.net/zhangpower1993/article/details/89016503

    @Configuration
    public class InterceptorConfig implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            // 拦截所有请求,通过判断是否有 登录验证相关注解 决定是否需要登录
            registry.addInterceptor(authenticationInterceptor())
                    .addPathPatterns("/**");
        }
        @Bean
        public AuthenticationInterceptor authenticationInterceptor() {
            //这个是自定义的拦截类,实现拦截后的操作
            return new AuthenticationInterceptor();
        }
    }
    

    自定义的拦截类

    实现HandlerInterceptor接口,该接口用于拦截后的操作

    public class AuthenticationInterceptor implements HandlerInterceptor {
        @Autowired
        UserService userService;
    
        @Autowired
        private TokenHelp tokenHelp;
    
        //预处理回调方法,实现处理器的预处理
        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
            // 从 http 请求头中取出 token
            String token = httpServletRequest.getHeader("token");
            // 如果不是映射到方法直接通过
            if (!(object instanceof HandlerMethod)) {
                return true;
            }
            HandlerMethod handlerMethod = (HandlerMethod) object;
            Method method = handlerMethod.getMethod();
            //检查是否有passtoken注释,有则跳过认证
            if (method.isAnnotationPresent(PassToken.class)) {
                PassToken passToken = method.getAnnotation(PassToken.class);
                if (passToken.required()) {
                    return true;
                }
            }
            //检查有没有需要管理员权限的注解
            if (method.isAnnotationPresent(UserAdminToken.class)) {
                UserAdminToken userAdminToken = method.getAnnotation(UserAdminToken.class);
                //对有这个请求验证的方法进行验证token
                if (userAdminToken.required()) {
                    // 验证 token
                    return tokenHelp.tokenValidate(token,true);
                }
            }
            //检查有没有需要用户权限的注解
            if (method.isAnnotationPresent(UserLoginToken.class)) {
                UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
                //对有这个请求验证的方法进行验证token
                if (userLoginToken.required()) {
                    // 验证 token
                    return tokenHelp.tokenValidate(token,false);
                }
            }
            return true;
        }
    //后处理回调方法,实现处理器的后处理(DispatcherServlet进行视图返回渲染之前进行调用)
        @Override
        public void postHandle(HttpServletRequest httpServletRequest,
                               HttpServletResponse httpServletResponse,
                               Object o, ModelAndView modelAndView) throws Exception {
    
        }
    //整个请求处理完毕回调方法,该方法也是需要当前对应的Interceptor的preHandle()的返回值为true时才会执行,一般用于资源清理
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest,
                                    HttpServletResponse httpServletResponse,
                                    Object o, Exception e) throws Exception {
        }
    
    

    登录接口

    当用于登录验证成功时,返回token

    //验证账号和密码是否正确
            if(userEntity.getUserName().equals(user.getUserName()) &&
                    userEntity.getPassword().equals(user.getPassword())){
                String token = tokenHelp.getToken(userEntity);
                Result result = new Result<>();
                Map<String,Object> map  = new HashMap<String,Object>();
                map.put("token",token);
                map.put("user",userEntity);
                return result.ok(map);
            }
    

    前端配置

    前端登录请求成功时,拿到服务器返回的token,存入全局变量,以layui为例

     //请求登入接口
          admin.req({
            url:  //实际使用请改成服务端真实接口
            ,data: JSON.stringify(data)//用户名和密码
            ,type: 'post'
            ,dataType:"json"
            ,headers: { 'Content-Type': 'application/json;charset=utf8' }
            ,done: function(res){
             
              //请求成功后,写入 access_token
              layui.sessionData(setter.tableName, {
                key: "token"
                ,value: res.data.token
              });
              //登入成功的提示与跳转
              layer.msg('登录成功', {
                offset: '15px'
                ,icon: 1
                ,time: 1000
              }, function(){
               location.href = 'index.html'; //后台主页
              });
            }
           
          }
          
          );
    

    在前端中的每次ajax请求的全局配置

     //给每次ajax请求默认加上token
      //全局配置
      $.ajaxSetup({
        beforeSend: function(jqXHR, settings) {
          jqXHR.setRequestHeader("token",layui.sessionData(layui.setter.tableName)['token']);
          }
          ,complete: function (req, status) { 
            if(req.status != 200){
              layer.msg(req.status+":"+req.responseJSON.message);
            }
            
          }
      });
    

    以后请求需要登录的接口都需要加上token,否则报错

    展开全文
  • SpringBoot整合token实现登录认证

    万次阅读 多人点赞 2019-06-14 17:43:32
    最近在做登录认证的时候,遇到了验证的问题,如何用token验证困扰了许久,所有在网上查询了许多博客,总结了一下,希望能帮助到大家,好了,废话不多说,直接上代码

    标题SpringBoot整合JWT实现登录认证

    1.pom.xml

    <dependencies>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-web</artifactId>
    		</dependency>
    
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-test</artifactId>
    			<scope>test</scope>
    		</dependency>
    		
    		<dependency>
    		      <groupId>com.auth0</groupId>
    		      <artifactId>java-jwt</artifactId>
    		      <version>3.4.0</version>
    		</dependency>
    		
    		 <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
            
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.3.2</version>
            </dependency>
            
    		 <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.47</version>
            </dependency>
    
    		<dependency>
    			<groupId>io.springfox</groupId>
    			<artifactId>springfox-swagger2</artifactId>
    			<version>2.8.0</version>
    		</dependency>
    		<dependency>
    			<groupId>io.springfox</groupId>
    			<artifactId>springfox-swagger-ui</artifactId>
    			<version>2.8.0</version>
    		</dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.0</version>
            </dependency>
    
        </dependencies>
    
    

    2.实体类

    @Data
    public class User {
    	private String id;
        private String username;
        private String password;
    }
    

    3.Mapper接口

    /**
     * @author qiaoyn
     * @date 2019/06/14
     */
    @Mapper
    public interface UserMapper {
    	
        User findByUsername(String username);
        
        User findUserById(String id);
    
    }
    

    4.service层

    @Service
    public class UserService {
        @Autowired
        private UserMapper userMapper;
        public User findByUsername(User user){
            return userMapper.findByUsername(user.getUsername());
        }
        public User findUserById(String userId) {
            return userMapper.findUserById(userId);
        }
    }
    
    /***
     * token 下发
    * @Title: TokenService.java 
    * @author qiaoyn
    * @date 2019/06/14
    * @version V1.0
     */
    @Service
    public class TokenService {
    
    	public String getToken(User user) {
    		Date start = new Date();
    		long currentTime = System.currentTimeMillis() + 60* 60 * 1000;//一小时有效时间
    		Date end = new Date(currentTime);
    		String token = "";
    		
    		token = JWT.create().withAudience(user.getId()).withIssuedAt(start).withExpiresAt(end)
    				.sign(Algorithm.HMAC256(user.getPassword()));
    		return token;
    	}
    }
    
    

    5.Api层

    @RestController
    public class UserApi {
    	@Autowired
    	UserService userService;
    	@Autowired
    	TokenService tokenService;
    
    	// 登录
    	@ApiOperation(value = "登陆", notes = "登陆")
    	@RequestMapping(value = "/login" ,method = RequestMethod.GET)
    	public Object login(User user, HttpServletResponse response) {
    		JSONObject jsonObject = new JSONObject();
    		User userForBase = new User();
    		userForBase.setId(userService.findByUsername(user).getId());
    		userForBase.setUsername(userService.findByUsername(user).getUsername());
    		userForBase.setPassword(userService.findByUsername(user).getPassword());
    		if (!userForBase.getPassword().equals(user.getPassword())) {
    			jsonObject.put("message", "登录失败,密码错误");
    			return jsonObject;
    		} else {
    			String token = tokenService.getToken(userForBase);
    			jsonObject.put("token", token);
    
    			Cookie cookie = new Cookie("token", token);
    			cookie.setPath("/");
    			response.addCookie(cookie);
    
    			return jsonObject;
    
    		}
    	}
    	/***
    	 * 这个请求需要验证token才能访问
    	 * 
    	 * @author: qiaoyn
    	 * @date 2019/06/14
    	 * @return String 返回类型
    	 */
    	@UserLoginToken
    	@ApiOperation(value = "获取信息", notes = "获取信息")
    	@RequestMapping(value = "/getMessage" ,method = RequestMethod.GET)
    	public String getMessage() {
    
    		// 取出token中带的用户id 进行操作
    		System.out.println(TokenUtil.getTokenUserId());
    
    		return "您已通过验证";
    	}
    }
    
    

    6.util

    /* 
    * @author qiaoyn
    * @date 2019/06/14
    * @version 1.0 
    */
    public class TokenUtil {
    
    	public static String getTokenUserId() {
    		String token = getRequest().getHeader("token");// 从 http 请求头中取出 token
    		String userId = JWT.decode(token).getAudience().get(0);
    		return userId;
    	}
    
    	/**
    	 * 获取request
    	 * 
    	 * @return
    	 */
    	public static HttpServletRequest getRequest() {
    		ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
    				.getRequestAttributes();
    		return requestAttributes == null ? null : requestAttributes.getRequest();
    	}
    }
    
    

    7.Interceptor

    /**
     * 拦截器
     * @author qiaoyn
     * @date 2019/06/14
     */
    public class AuthenticationInterceptor implements HandlerInterceptor {
        @Autowired
        UserService userService;
        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
            String token = httpServletRequest.getHeader("token");// 从 http 请求头中取出 token
            // 如果不是映射到方法直接通过
            if(!(object instanceof HandlerMethod)){
                return true;
            }
            HandlerMethod handlerMethod=(HandlerMethod)object;
            Method method=handlerMethod.getMethod();
            //检查是否有passtoken注释,有则跳过认证
            if (method.isAnnotationPresent(PassToken.class)) {
                PassToken passToken = method.getAnnotation(PassToken.class);
                if (passToken.required()) {
                    return true;
                }
            }
            //检查有没有需要用户权限的注解
            if (method.isAnnotationPresent(UserLoginToken.class)) {
                UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
                if (userLoginToken.required()) {
                    // 执行认证
                    if (token == null) {
                        throw new RuntimeException("无token,请重新登录");
                    }
                    // 获取 token 中的 user id
                    String userId;
                    try {
                        userId = JWT.decode(token).getAudience().get(0);
                    } catch (JWTDecodeException j) {
                        throw new RuntimeException("401");
                    }
                    User user = userService.findUserById(userId);
                    if (user == null) {
                        throw new RuntimeException("用户不存在,请重新登录");
                    }
                    // 验证 token
                    JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
                    try {
                        jwtVerifier.verify(token);
                    } catch (JWTVerificationException e) {
                        throw new RuntimeException("401");
                    }
                    return true;
                }
            }
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    
        }
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    
        }
    }
    
    

    8.cofig

    /***
     * 新建Token拦截器
    * @Title: InterceptorConfig.java 
    * @author qiaoyn
    * @date 2019/06/14
    * @version V1.0
     */
    @Configuration
    public class InterceptorConfig implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(authenticationInterceptor())
                    .addPathPatterns("/**");    // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
        }
        @Bean
        public AuthenticationInterceptor authenticationInterceptor() {
            return new AuthenticationInterceptor();
        }
    	@Override
    	public void addArgumentResolvers(List<HandlerMethodArgumentResolver> arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void addCorsMappings(CorsRegistry arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void addFormatters(FormatterRegistry arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void addResourceHandlers(ResourceHandlerRegistry arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void addViewControllers(ViewControllerRegistry arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void configureAsyncSupport(AsyncSupportConfigurer arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void configureContentNegotiation(ContentNegotiationConfigurer arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void configureMessageConverters(List<HttpMessageConverter<?>> arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void configurePathMatch(PathMatchConfigurer arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void configureViewResolvers(ViewResolverRegistry arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void extendMessageConverters(List<HttpMessageConverter<?>> arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public MessageCodesResolver getMessageCodesResolver() {
    		// TODO Auto-generated method stub
    		return null;
    	}
    	@Override
    	public Validator getValidator() {
    		// TODO Auto-generated method stub
    		return null;
    	}
    	
    }
    
    

    9.annotation

    /***
     * 用来跳过验证的 PassToken
     * @author qiaoyn
     * @date 2019/06/14
     */
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface PassToken {
        boolean required() default true;
    }
    
    /**
     * 用于登录后才能操作的token
     * @author qiaoyn
     * @date 2019/06/14
     */
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface UserLoginToken {
        boolean required() default true;
    }
    
    /*RetentionPolicy.RUNTIME:这种类型的Annotations将被JVM保留,
    所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用。*/
    

    10.mapper.xml

    <?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.example.demo.mapper.UserMapper">
        <select id="findByUsername" resultType="com.example.demo.entity.User">
          SELECT id,password
          FROM user
          WHERE
          username=#{username}
        </select>
        <select id="findUserById" resultType="com.example.demo.entity.User">
            SELECT username,password
            FROM user
            WHERE
            id=#{id}
        </select>
    
    </mapper>
    

    11.测试
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    数据库文件如下所示
    在这里插入图片描述
    好了,今天分享就到此了。

    展开全文
  • 登录认证即分为登录和认证两部分,下面聊下他们的实现逻辑。 1 登录 前端调用后端的登录接口,后端验证用户名和密码等成功后,则做下面两个主要工作: 1 以用户id为key,生成的token为value,缓存到redis中并设置...
  • token实现登录状态保持/身份认证的机制

    万次阅读 多人点赞 2018-12-19 10:18:32
    实现登录状态保持与身份认证的方式通常有两种:session结合数据库、token。 两者相比较,token有较多优点。 ① token可以存储在任何位置(比如cookie或local storage) ② token更容易跨域 ③ token过期时可以...
  • 1.用户注册时生成Token @ApiOperation(value = "用户注册", notes = "用户注册", httpMethod = "POST") @PostMapping("/regist") public IMOOCJSONResult regist(@RequestBody UserBO userBO, HttpServletRequest...
  • 一般的登录权限框架有spring security和shiro两种,但是如果只是单单实现一个登录功能,没有更多的权限交互,引入沉重的框架来处理反而会出现很多问题或者加重程序的处理效率,所以,用自定义的token实现登录功能在一些...
  • 所以登录和退出时需要自己判断是否获得token值并且做出登录和退出的路由跳转操作。首先我们通过接口获得token值。 window.sessionStorage.setItem('token',res.data.token) // console.log(sessionStorage.getItem...
  • 采用token加密登录 简单介绍token 1.什么是tokentoken作用是什么 (1)token是一段经过后端处理(加密算法)的特殊字符,后端在前端登录时,会返回该字符,前端拿到这个字符后会将其存入cookie (2) 项目自动...
  • SpringBoot框架集成token实现登录校验功能(APP)

    千次阅读 热门讨论 2019-04-18 14:00:56
    公司新项目,需要做移动端(Android和IOS),登录模块,两个移动端人员提出用token来校验登录状态,一脸懵懵的,没做过,对于token的基本定义都模棱两可,然后查资料查查查,最终OK完成,写篇博客记录一下 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,385
精华内容 1,754
关键字:

token实现登录