登录模块 用户认证 SpringSecurity +Oauth2+Jwt流程分析

认证

Oauth实现微信登录流程

安全认证:你是谁,能干什么

第三方登录授权过程



1. 用户访问第三方资源,第三方请求微信服务器发送授权请求给用户

2. 用户确认授权后,返回授权码给第三方

3. 第三方拿到授权码后,携带授权码向微信申请令牌

4. 第三方拿到令牌后,携带令牌向微信请求用户的基本信息

5. 微信资源服务器根据访问令牌,返回给第三方用户的基本信息

3-5的交互过程用户看不到,用户只能看到登录成功,显示自己的基本信息


账号密码注册登录

注册时候前端可以先加密,后端再加密一次,这样如果请求被拦截了也不会显示明文密码。

账号密码登录

1. 账号密码登录,网关对于登录和一些静态资源是放行的,可以访问。然后这里是验证登录和生成令牌的过程,这里采用jwt的方式经过RSA的私钥生成令牌,公钥去解析。

2. 在认证服务的过程中会去链接数据库,访问两个数据库,一个是通过fegin的远程调用访问user,role,perssion表(都是多对多),这样返回的时候就会携带用户和权限信息,一个是oauth_client_details(配置数据库链接,自动访问)拿到第三方授权的账号密码(自关联)。有用户名密码查询正确,把uid和生成令牌的jti形成键值对放入cookie中,redis存放的是jti和对应的token信息,这样就能通过cookie中的uid找到jti,再找到redis中的token可以进行解析了

3. 当用户访问服务的时候,会经过微服务网关,这里有两种配置解析的方式。

1.公钥存放在网关,判断cookie,redis中的指定值是否存在,最后通过公钥去解析令牌是否合法,如果都没问题就放行

2.如果私钥配置在微服务上的话,网关判断cookie和redis非空后,设置一下请求的响应头

request.mutate().header("Authorization","Bearer "+jwt);

这就是令牌的传递,这样其他微服务就不需要再去cookie和redis去找令牌了,过来的时候就携带了


现在就分为认证服务资源服务

登录授权后如果有改变权限或者增加微服务地址怎么动态的增加呢?

可以在后台维护一张字典表,专门用作配置,比如要令牌资源路径,或者订单状态,维护一对多的两张表,保存在DB中,取完保存在redis中,用Quartz定时组件来完成定时的更新。


权限控制


用户->角色->权限


1.类方式

···java

/*****

* 自定义授权认证类

*/

@Service

public class UserDetailsServiceImpl implements UserDetailsService {

@Autowired

    ClientDetailsService clientDetailsService;

@Autowired

    private UserFeign userFeign;

/****

    * 自定义授权认证

    * @param username

    * @return

    * @throws UsernameNotFoundException

    */

    @Override

    public UserDetails loadUserByUsername(String username)throws UsernameNotFoundException {

//取出身份,如果身份为空说明没有认证

        Authentication authentication =SecurityContextHolder.getContext().getAuthentication();

//没有认证统一采用httpbasic认证,httpbasic中存储了client_id和client_secret,开始认证client_id和client_secret

        if(authentication==null){

ClientDetails clientDetails =clientDetailsService.loadClientByClientId(username);

if(clientDetails!=null){

//秘钥

                String clientSecret =clientDetails.getClientSecret();

//静态方式

                //return new User(username,new BCryptPasswordEncoder().encode(clientSecret), AuthorityUtils.commaSeparatedStringToAuthorityList(""));

                //数据库查找方式

                return new User(username,clientSecret,AuthorityUtils.commaSeparatedStringToAuthorityList(""));

}

}

if (StringUtils.isEmpty(username)) {

return null;

}

//根据用户名查询用户信息

        //String pwd = new BCryptPasswordEncoder().encode("itheima");

        com.changgou.user.pojo.User user =userFeign.findUserInfo(username);

//创建User对象

        String permissions ="salesman,accountant,user";

UserJwt userDetails =new UserJwt(username,user.getPassword(),AuthorityUtils.commaSeparatedStringToAuthorityList(permissions));

return userDetails;

}

}

···

2.注解方式

ResourceServerConfig类上添加@EnableGlobalMethodSecurity注解,用于开启@PreAuthorize的支持

···java

@Configuration

@EnableResourceServer

@EnableGlobalMethodSecurity(prePostEnabled =true, securedEnabled =true)//激活方法上的PreAuthorize注解

public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

//公钥

    private static final String PUBLIC_KEY ="public.key";

/***

    * 定义JwtTokenStore

    * @param jwtAccessTokenConverter

    * @return

*/

    @Bean

    public TokenStore tokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) {

return new JwtTokenStore(jwtAccessTokenConverter);

}

/***

    * 定义JJwtAccessTokenConverter

* @return

*/

    @Bean

    public JwtAccessTokenConverter jwtAccessTokenConverter() {

JwtAccessTokenConverter converter =new JwtAccessTokenConverter();

converter.setVerifierKey(getPubKey());

return converter;

}

/**

    * 获取非对称加密公钥 Key

    * @return 公钥 Key

*/

    private String getPubKey() {

Resource resource =new ClassPathResource(PUBLIC_KEY);

try {

InputStreamReader inputStreamReader =new InputStreamReader(resource.getInputStream());

BufferedReader br =new BufferedReader(inputStreamReader);

return br.lines().collect(Collectors.joining("\n"));

}catch (IOException ioe) {

return null;

}

}

/***

    * Http安全配置,对每个到达系统的http请求链接进行校验

    * @param http

    * @throws Exception

    */

    @Override

    public void configure(HttpSecurity http)throws Exception {

//所有请求必须认证通过

        http.authorizeRequests()

//下边的路径放行

                .antMatchers(

"/user/add","/user/load/**").//配置地址放行

                permitAll()

.anyRequest().

authenticated();//其他地址需要认证授权

    }

}

···

接下来可以在方法上加入@PreAuthorize(具体控制)

如果希望一个方法能被多个角色访问,配置:@PreAuthorize("hasAnyAuthority('admin','user')")

如果希望一个类都能被多个角色访问,在类上配置:@PreAuthorize("hasAnyAuthority('admin','user')")

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353